目 录
第1章 Java性能演变史:编程语言与虚拟机 1
1.1 Java生态系统的诞生 2
1.2 JDK的演进历程 2
1.3 Java HotSpot虚拟机及其编译策略 3
1.3.1 HotSpot执行引擎的演变 3
1.3.2 解释器和JIT编译 5
1.3.3 编译日志的打印 5
1.3.4 分层编译机制 6
1.3.5 客户端和服务器端编译器 7
1.3.6 分段代码缓存 7
1.3.7 自适应优化和反向优化 9
1.4 HotSpot内存管理单元:垃圾收集器 12
1.4.1 分代垃圾收集、STW算法和并发算法 13
1.4.2 新生代收集与弱分代假说 14
1.4.3 老年代收集和触发机制 15
1.4.4 并行和并发垃圾收集线程及其配置 16
1.5 Java语言及其生态系统的发展 18
1.5.1 Java 1.1至Java 1.4.2(J2SE 1.4.2) 18
1.5.2 Java 5 (J2SE 5.0) 19
1.5.3 Java 6 (Java SE 6) 22
1.5.4 Java 7 (Java SE 7) 24
1.5.5 Java 8 (Java SE 8) 28
1.5.6 Java 9(Java SE 9)至Java 16 (Java SE 16) 30
1.5.7 Java 17 (Java SE 17) 38
1.6 提升性能与拥抱变革 40
第2章 Java类型系统的发展及其性能影响 41
2.1 J2SE 5.0前的原始类型和字面量 42
2.2 J2SE 5.0前的引用类型 43
2.2.1 接口 43
2.2.2 类 45
2.2.3 数组 46
2.3 J2SE 5.0至Java SE 8类型系统的发展 47
2.3.1 枚举类型 47
2.3.2 注解 48
2.3.3 Java SE 8中其他重要改进 48
2.4 Java 9与Java 10类型系统的发展 50
2.5 Java 11至Java 17类型系统的发展 52
2.5.1 switch表达式 52
2.5.2 密封类 54
2.5.3 记录类型 55
2.6 Java 17之后:Valhalla项目 55
2.6.1 现有类型系统的性能影响 56
2.6.2 值类对内存管理的影响 61
2.6.3 重定义原始类型泛型支持 61
2.6.4 Valhalla项目 62
2.6.5 早期访问版本:先进的Valhalla理念 63
2.6.6 用例分析:理论与实际 64
2.6.7 不同语言间的对比 64
2.7 本章小结 65
第3章 从单体到模块化的演进之路 67
3.1 Java模块化系统概述 67
3.1.1 模块化系统介绍 68
3.1.2 模块化示例 68
3.1.3 编译和运行细节 70
3.1.4 新模块引入 70
3.2 从单体到模块化的JDK演变 75
3.3 JDK 11及更高版本中的模块化JDK 75
3.4 JDK 17模块化服务实现 75
3.4.1 服务提供者 76
3.4.2 服务消费者 77
3.4.3 示例 77
3.4.4 实现细节 78
3.5 JAR地狱和Jigsaw Layer 80
3.5.1 解决JAR地狱示例 81
3.5.2 实现细节 82
3.6 OSGi 87
3.6.1 OSGi概览 87
3.6.2 OSGi与Java模块层的相似之处 88
3.6.3 OSGi与Java模块层的差异 88
3.7 jdeps、jlink、jdeprscan和jmod简介 89
3.7.1 jdeps 89
3.7.2 jdeprscan 90
3.7.3 jmod 91
3.7.4 jlink 92
3.8 本章小结 93
3.8.1 性能影响 93
3.8.2 工具和未来展望 93
3.8.3 拥抱模块化编程范式 93
第4章 JVM统一日志接口 95
4.1 统一日志记录的必要性 95
4.2 统一日志与基础设施 96
4.3 统一日志系统中的标签 97
4.3.1 日志标签 97
4.3.2 标签指定 98
4.3.3 识别缺失信息 99
4.4 日志级别、输出和装饰器 99
4.4.1 日志级别 99
4.4.2 装饰器 101
4.4.3 日志输出 102
4.5 使用统一日志系统的示例 103
4.5.1 基准测试和性能测试 104
4.5.2 工具和技术 105
4.6 优化和管理统一日志系统 105
4.7 异步日志和统一日志系统 106
4.7.1 异步日志记录的优势 106
4.7.2 Java中异步日志实现 107
4.7.3 最佳实践和注意事项 108
4.8 JDK 11与JDK 17的日志增强功能 109
4.8.1 JDK 11 109
4.8.2 JDK 17 110
4.9 本章小结 110
第5章 端到端性能优化:JMH和微基准测试 111
5.1 本章简介 111
5.2 软件工程的核心支柱:性能工程 112
5.2.1 解码软件工程的各个层面 112
5.2.2 关键质量属性:性能 112
5.2.3 了解和评估性能 113
5.2.4 定义服务质量 113
5.2.5 衡量性能需求的成功标准 114
5.3 衡量Java应用程序性能的指标 114
5.3.1 占用空间 115
5.3.2 响应时间 118
5.3.3 吞吐量 119
5.3.4 可用性 119
5.3.5 响应时间与可用性 120
5.3.6 应用程序响应时间的时间轴分析 121
5.4 硬件对性能的影响 123
5.4.1 解码硬件与软件的动态关系 124
5.4.2 性能交响曲:编程语言、处理器和内存模型 125
5.4.3 性能提升之道:优化系统协作 126
5.4.4 内存模型:解读线程动态和性能影响 127
5.4.5 硬件上的并发 130
5.4.6 并发计算中的秩序机制:屏障、栅栏和volatile变量 132
5.4.7 深入理解原子性:Java内存模型和先行发生原则 133
5.4.8 多处理器系统中的并发内存访问和一致性 135
5.4.9 结合我在AMD、Sun Microsystems和ARM的经历深度挖掘NUMA 135
5.4.10 理论与实践的桥梁:并发、库和高级工具 139
5.5 一种灵活且全面的性能工程方法论 139
5.5.1 实验设计 139
5.5.2 自下而上的方法论 140
5.5.3 自上而下的方法论 142
5.5.4 制定工作说明书 142
5.5.5 一种自上而下的性能优化流程 143
5.5.6 以工作说明书为基础调查子系统 144
5.5.7 本节要点 150
5.6 性能基准的重要性 151
5.6.1 关键性能指标 151
5.6.2 从规划到分析建立性能基准制度 152
5.6.3 JVM内存管理基准测试综合指南 154
5.6.4 为何需要基准测试工具 156
5.6.5 Java微基准测试套件在性能优化中的作用 157
5.6.6 使用Maven入门Java微基准测试套件 158
5.6.7 在JMH中编写、构建和运行第一个微基准 158
5.6.8 基准测试阶段:预热和测量 160
5.6.9 循环优化和@Operations PerInvocation注解 161
5.6.10 JMH的基准模式 161
5.6.11 理解JMH中的分析器 162
5.6.12 JMH中的关键注解 162
5.6.13 使用JMH进行JVM基准测试 163
5.6.14 使用perfasm分析JMH基准 165
5.7 本章小结 166
第6章 OpenJDK中的高级内存管理和垃圾收集 167
6.1 本章简介 167
6.2 Java垃圾收集器概述 168
6.3 TLAB和PLAB 169
6.4 利用NUMA感知型的垃圾收集器优化内存访问 171
6.5 探索垃圾收集器的改进 173
6.5.1 通过G1垃圾收集器深入了解高级堆管理 174
6.5.2 区域化堆的优势 176
6.5.3 优化G1垃圾收集器参数实现峰值性能 178
6.5.4 适用于多TB堆内存的可扩展、低延迟的ZGC 186
6.6 垃圾收集器的未来趋势 198
6.7 评估垃圾收集器性能的实用技巧 200
6.8 评估不同工作负载下垃圾收集器的性能 202
6.8.1 事务工作负载类型 202
6.8.2 本节内容回顾 203
6.9 实时数据集压力 204
6.9.1 数据生命周期模式 204
6.9.2 对不同垃圾收集算法的影响 205
6.9.3 优化内存管理 205
第7章 运行时性能优化:聚焦字符串、锁及其他 207
7.1 本章简介 207
7.2 字符串优化 208
7.2.1 HotSpot虚拟机中的字面量和驻留字符串优化 209
7.2.2 字符串去重优化与G1垃圾收集器 211
7.2.3 减少字符串的内存占用 212
7.3 提升多线程性能:Java线程同步 223
7.3.1 监视器锁的作用 225
7.3.2 OpenJDK HotSpot虚拟机中的锁类型 225
7.3.3 代码示例和分析 226
7.3.4 Java锁机制的发展 228
7.3.5 自Java 9以来对竞争锁的优化 230
7.3.6 关于可视化竞争锁优化的性能工程实践 232
7.3.7 竞争锁优化的一些反思 242
7.3.8 一种间接锁改进:自旋等待提示 243
7.4 从Thread-Per-Task模型转向更具可扩展性的模型 245
7.4.1 传统的一对一线程映射 246
7.4.2 通过Thread-Per-Request模型提高可扩展性 246
7.4.3 虚拟线程重塑Java的并发编程 251
7.5 本章小结 256
第8章 使用OpenJDK HotSpot 虚拟机加速进入稳定状态 257
8.1 本章简介 257
8.2 优化JVM启动和预热的技术 258
8.3 Java应用程序从解码到稳定状态的时间 258
8.3.1 准备、就绪、启动 258
8.3.2 启动JVM的各个阶段 259
8.3.3 达到应用程序的稳定状态 260
8.3.4 应用程序的生命周期 261
8.4 启动和加速期间的状态管理 263
8.4.1 启动期间的状态 263
8.4.2 进入加速阶段和稳定状态 263
8.4.3 高效状态管理的优势 264
8.4.4 类数据共享 265
8.4.5 AOT编译 266
8.5 GraalVM彻底改变Java的稳态时间 272
8.6 新兴技术:用于检查点及恢复功能的CRIU和CRaC项目 274
8.7 优化无服务器环境和其他环境中的启动和加速阶段 277
8.7.1 无服务器计算和JVM优化 278
8.7.2 在容器化环境中确保快速启动和高效扩展 279
8.7.3 GraalVM的当今贡献 279
8.7.4 本节要点小结 279
8.8 利用OpenJDK HotSpot虚拟机提升预热性能 281
8.8.1 编译器的改进 281
8.8.2 分段代码缓存和Leyden项目的增强功能 284
8.8.3 从永久代到元空间向 峰值性能飞跃 284
8.9 本章小结 287
第9章 使用异构硬件打造JVM性能的未来 289
9.1 异构硬件和JVM简介 289
9.2 云计算中的异构硬件 291
9.2.1 硬件异构性 292
9.2.2 API兼容性和Hypervisor限制 292
9.2.3 性能权衡 293
9.2.4 资源竞争 293
9.2.5 云计算的特定限制 294
9.3 编程语言设计和工具链的作用 294
9.4 案例研究 296
9.4.1 LWJGL:一个基础示例 297
9.4.2 Aparapi:连接Java和OpenCL的桥梁 300
9.4.3 Sumatra项目:一项重大努力 303
9.4.4 TornadoVM:硬件加速器专用JVM 306
9.4.5 Panama项目:新视野 309
9.5 JVM与Panama项目 314
9.5.1 高级JVM语言API和本地库 315
9.5.2 Vector API和向量化数据处理系统 315
9.5.3 用于数据访问、缓存和格式化的加速器描述符 315
9.5.4 未来已来 316
9.6 结束语:畅想JVM性能工程 317
