[套装书]深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)+深入理解Android:Java虚拟机ART(2册)

更多详情

内容简介:

---------------------------深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)---------------------------

《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》第1版两年内印刷近10次,4家网上书店的评论近4?000条,98%以上的评论全部为5星级的好评,是整个Java图书领域公认的经典著作和超级畅销书,繁体版在台湾也十分受欢迎。第2版在第1版的基础上做了很大的改进:根据最新的JDK 1.7对全书内容进行了全面的升级和补充;增加了大量处理各种常见JVM问题的技巧和最佳实践;增加了若干与生产环境相结合的实战案例;对第1版中的错误和不足之处的修正;等等。第2版不仅技术更新、内容更丰富,而且实战性更强。
全书共分为五大部分,围绕内存管理、执行子系统、程序编译与优化、高效并发等核心主题对JVM进行了全面而深入的分析,深刻揭示了JVM的工作原理。第一部分从宏观的角度介绍了整个Java技术体系、Java和JVM的发展历程、模块化,以及JDK的编译,这对理解本书后面内容有重要帮助。第二部分讲解了JVM的自动内存管理,包括虚拟机内存区域的划分原理以及各种内存溢出异常产生的原因;常见的垃圾收集算法以及垃圾收集器的特点和工作原理;常见虚拟机监控与故障处理工具的原理和使用方法。第三部分分析了虚拟机的执行子系统,包括类文件结构、虚拟机类加载机制、虚拟机字节码执行引擎。第四部分讲解了程序的编译与代码的优化,阐述了泛型、自动装箱拆箱、条件编译等语法糖的原理;讲解了虚拟机的热点探测方法、HotSpot的即时编译器、编译触发条件,以及如何从虚拟机外部观察和分析JIT编译的数据和结果;第五部分探讨了Java实现高效并发的原理,包括JVM内存模型的结构和操作;原子性、可见性和有序性在Java内存模型中的体现;先行发生原则的规则和使用;线程在Java语言中的实现原理;虚拟机实现高效并发所做的一系列锁优化措施。

---------------------------深入理解Android:Java虚拟机ART---------------------------

内容介绍
这是一部从源代码角度分析和讲解Android虚拟机ART的鸿篇巨著,核心内容和价值体现在3个方面:
第一,细致、深入地分析了ART虚拟机的架构、设计与实现原理,能让读者对ART虚拟机有透彻了解;
第二,能让Andriod系统工程师和应用工程师从底层了解整个Android系统的运行机理,从而写出更高质量的应用;
第三,Java虚拟机是一个“庞然大物”,学习和理解的门槛较高,ART是迄今应用最为广泛的JVM实现,本书为读者学习JVM提供了独特的视角和更为容易的路径。
全书共14章:
第1章介绍了在学习ART虚拟机前需要准备的工具和环境,以及本书的内容结构和阅读注意事项,建议仔细读和反复读;
第2~4章详细讲解了Class文件、dex文件和ELF文件的格式和内容,理解Class文件是学习JVM的第一步,dex和ELF者是学习Dalvik虚拟机和ART虚拟机的的前提和基础;
第5章详细讲解了ART虚拟机的实现语言C++11,是阅读ART源代码必备的知识;
第6~8章详细讲解了ART虚拟机中与编译和Runtime相关的大量知识,这是虚拟机的核心和难点;
第9章详细讲解了dex字节码转机器码的核心进程dex2oat以及.oat和.art的文件格式;
第10~11章详细讲解了虚拟机的解释执行、JIT部分以及异常的投递和处理的过程,以及JNI在ART虚拟机中的实现。
第12~14章详细讲解了虚拟机中Java线程的执行、内存分配和释放、垃圾回收的原理与实现。
本书是经典丛书“深入理解Android”系列的第8本,继承了该系列图书严谨、细致、深入、编排考究的优点,相信所有Android工程师和Java工程师都能从中受益。

目录:

---------------------------深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)---------------------------

《深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)》
前言
第一部分 走近Java
第1章 走近Java / 2
1.1 概述 / 2
1.2 Java技术体系 / 3
1.3 Java发展史 / 5
1.4 Java虚拟机发展史 / 9
1.4.1 Sun Classic / Exact VM / 9
1.4.2 Sun HotSpot VM / 11
1.4.3 Sun Mobile-Embedded VM / Meta-Circular VM / 12
1.4.4 BEA JRockit / IBM J9 VM / 13
1.4.5 Azul VM / BEA Liquid VM / 14
1.4.6 Apache Harmony / Google Android Dalvik VM / 14
1.4.7 Microsoft JVM及其他 / 15
1.5 展望Java技术的未来 / 16
1.5.1 模块化 / 17
1.5.2 混合语言 / 17
1.5.3 多核并行 / 19
1.5.4 进一步丰富语法 / 20
1.5.5 64位虚拟机 / 21
1.6 实战:自己编译JDK / 22
1.6.1 获取JDK源码 / 22
1.6.2 系统需求 / 24
1.6.3 构建编译环境 / 25
1.6.4 进行编译 / 26
1.6.5 在IDE工具中进行源码调试 / 31
1.7 本章小结 / 35
第二部分 自动内存管理机制
第2章 Java内存区域与内存溢出异常 / 38
2.1 概述 / 38
2.2 运行时数据区域 / 38
2.2.1 程序计数器 / 39
2.2.2 Java虚拟机栈 / 39
2.2.3 本地方法栈 / 40
2.2.4 Java堆 / 41
2.2.5 方法区 / 41
2.2.6 运行时常量池 / 42
2.2.7 直接内存 / 43
2.3 HotSpot虚拟机对象探秘 / 43
2.3.1 对象的创建 / 44
2.3.2 对象的内存布局 / 47
2.3.3 对象的访问定位 / 48
2.4 实战:OutOfMemoryError异常 / 50
2.4.1 Java堆溢出 / 51
2.4.2 虚拟机栈和本地方法栈溢出 / 53
2.4.3 方法区和运行时常量池溢出 / 56
2.4.4 本机直接内存溢出 / 59
2.5 本章小结 / 60
第3章 垃圾收集器与内存分配策略 / 61
3.1 概述 / 61
3.2 对象已死吗 / 62
3.2.1 引用计数算法 / 62
3.2.2 可达性分析算法 / 64
3.2.3 再谈引用 / 65
3.2.4 生存还是死亡 / 66
3.2.5 回收方法区 / 68
3.3 垃圾收集算法 / 69
3.3.1 标记-清除算法 / 69
3.3.2 复制算法 / 70
3.3.3 标记-整理算法 / 71
3.3.4 分代收集算法 / 72
3.4 HotSpot的算法实现 / 72
3.4.1 枚举根节点 / 72
3.4.2 安全点 / 73
3.4.3 安全区域 / 74
3.5 垃圾收集器 / 75
3.5.1 Serial收集器 / 76
3.5.2 ParNew收集器 / 77
3.5.3 Parallel Scavenge收集器 / 79
3.5.4 Serial Old收集器 / 80
3.5.5 Parallel Old收集器 / 80
3.5.6 CMS收集器 / 81
3.5.7 G1收集器 / 84
3.5.8 理解GC日志 / 89
3.5.9 垃圾收集器参数总结 / 90
3.6 内存分配与回收策略 / 91
3.6.1 对象优先在Eden分配 / 91
3.6.2 大对象直接进入老年代 / 93
3.6.3 长期存活的对象将进入老年代 / 95
3.6.4 动态对象年龄判定 / 97
3.6.5 空间分配担保 / 98
3.7 本章小结 / 100
第4章 虚拟机性能监控与故障处理工具 / 101
4.1 概述 / 101
4.2 JDK的命令行工具 / 101
4.2.1 jps:虚拟机进程状况工具 / 104
4.2.2 jstat:虚拟机统计信息监视工具 / 105
4.2.3 jinfo:Java配置信息工具 / 106
4.2.4 jmap:Java内存映像工具 / 107
4.2.5 jhat:虚拟机堆转储快照分析工具 / 108
4.2.6 jstack:Java堆栈跟踪工具 / 109
4.2.7 HSDIS:JIT生成代码反汇编 / 111
4.3 JDK的可视化工具 / 114
4.3.1 JConsole:Java监视与管理控制台 / 115
4.3.2 VisualVM:多合一故障处理工具 / 122
4.4 本章小结 / 131
第5章 调优案例分析与实战 / 132
5.1 概述 / 132
5.2 案例分析 / 132
5.2.1 高性能硬件上的程序部署策略 / 132
5.2.2 集群间同步导致的内存溢出 / 135
5.2.3 堆外内存导致的溢出错误 / 136
5.2.4 外部命令导致系统缓慢 / 137
5.2.5 服务器JVM进程崩溃 / 138
5.2.6 不恰当数据结构导致内存占用过大 / 139
5.2.7 由Windows虚拟内存导致的长时间停顿 / 141
5.3 实战:Eclipse运行速度调优 / 142
5.3.1 调优前的程序运行状态 / 142
5.3.2 升级JDK 1.6的性能变化及兼容问题 / 145
5.3.3 编译时间和类加载时间的优化 / 150
5.3.4 调整内存设置控制垃圾收集频率 / 153
5.3.5 选择收集器降低延迟 / 157
5.4 本章小结 / 160
第三部分 虚拟机执行子系统
第6章 类文件结构 / 162
6.1 概述 / 162
6.2 无关性的基石 / 162
6.3 Class类文件的结构 / 164
6.3.1 魔数与Class文件的版本 / 166
6.3.2 常量池 / 167
6.3.3 访问标志 / 173
6.3.4 类索引、父类索引与接口索引集合 / 174
6.3.5 字段表集合 / 175
6.3.6 方法表集合 / 178
6.3.7 属性表集合 / 180
6.4 字节码指令简介 / 196
6.4.1 字节码与数据类型 / 197
6.4.2 加载和存储指令 / 199
6.4.3 运算指令 / 200
6.4.4 类型转换指令 / 202
6.4.5 对象创建与访问指令 / 203
6.4.6 操作数栈管理指令 / 203
6.4.7 控制转移指令 / 204
6.4.8 方法调用和返回指令 / 204
6.4.9 异常处理指令 / 205
6.4.10 同步指令 / 205
6.5 公有设计和私有实现 / 206
6.6 Class文件结构的发展 / 207
6.7 本章小结 / 208
第7章 虚拟机类加载机制 / 209
7.1 概述 / 209
7.2 类加载的时机 / 210
7.3 类加载的过程 / 214
7.3.1 加载 / 214
7.3.2 验证 / 216
7.3.3 准备 / 219
7.3.4 解析 / 220
7.3.5 初始化 / 225
7.4 类加载器 / 227
7.4.1 类与类加载器 / 228
7.4.2 双亲委派模型 / 229
7.4.3 破坏双亲委派模型 / 233
7.5 本章小结 / 235
第8章 虚拟机字节码执行引擎 / 236
8.1 概述 / 236
8.2 运行时栈帧结构 / 236
8.2.1 局部变量表 / 238
8.2.2 操作数栈 / 242
8.2.3 动态连接 / 243
8.2.4 方法返回地址 / 243
8.2.5 附加信息 / 244
8.3 方法调用 / 244
8.3.1 解析 / 244
8.3.2 分派 / 246
8.3.3 动态类型语言支持 / 258
8.4 基于栈的字节码解释执行引擎 / 269
8.4.1 解释执行 / 269
8.4.2 基于栈的指令集与基于寄存器的指令集 / 270
8.4.3 基于栈的解释器执行过程 / 272
8.5 本章小结 / 275
第9章 类加载及执行子系统的案例与实战 / 276
9.1 概述 / 276
9.2 案例分析 / 276
9.2.1 Tomcat:正统的类加载器架构 / 276
9.2.2 OSGi:灵活的类加载器架构 / 279
9.2.3 字节码生成技术与动态代理的实现 / 282
9.2.4 Retrotranslator:跨越JDK版本 / 286
9.3 实战:自己动手实现远程执行功能 / 289
9.3.1 目标 / 290
9.3.2 思路 / 290
9.3.3 实现 / 291
9.3.4 验证 / 298
9.4 本章小结 / 299
第四部分 程序编译与代码优化
第10章 早期(编译期)优化 / 302
10.1 概述 / 302
10.2 Javac编译器 / 303
10.2.1 Javac的源码与调试 / 303
10.2.2 解析与填充符号表 / 305
10.2.3 注解处理器 / 307
10.2.4 语义分析与字节码生成 / 307
10.3 Java语法糖的味道 / 311
10.3.1 泛型与类型擦除 / 311
10.3.2 自动装箱、拆箱与遍历循环 / 315
10.3.3 条件编译 / 317
10.4 实战:插入式注解处理器 / 318
10.4.1 实战目标 / 318
10.4.2 代码实现 / 319
10.4.3 运行与测试 / 326
10.4.4 其他应用案例 / 327
10.5 本章小结 / 328
第11章 晚期(运行期)优化 / 329
11.1 概述 / 329
11.2 HotSpot虚拟机内的即时编译器 / 329
11.2.1 解释器与编译器 / 330
11.2.2 编译对象与触发条件 / 332
11.2.3 编译过程 / 337
11.2.4 查看及分析即时编译结果 / 339
11.3 编译优化技术 / 345
11.3.1 优化技术概览 / 346
11.3.2 公共子表达式消除 / 350
11.3.3 数组边界检查消除 / 351
11.3.4 方法内联 / 352
11.3.5 逃逸分析 / 354
11.4 Java与C/C++的编译器对比 / 356
11.5 本章小结 / 358
第五部分 高效并发
第12章 Java内存模型与线程 / 360
12.1 概述 / 360
12.2 硬件的效率与一致性 / 361
12.3 Java内存模型 / 362
12.3.1 主内存与工作内存 / 363
12.3.2 内存间交互操作 / 364
12.3.3 对于volatile型变量的特殊规则 / 366
12.3.4 对于long和double型变量的特殊规则 / 372
12.3.5 原子性、可见性与有序性 / 373
12.3.6 先行发生原则 / 375
12.4 Java与线程 / 378
12.4.1 线程的实现 / 378
12.4.2 Java线程调度 / 381
12.4.3 状态转换 / 383
12.5 本章小结 / 384
第13章 线程安全与锁优化 / 385
13.1 概述 / 385
13.2 线程安全 / 385
13.2.1 Java语言中的线程安全 / 386
13.2.2 线程安全的实现方法 / 390
13.3 锁优化 / 397
13.3.1 自旋锁与自适应自旋 / 398
13.3.2 锁消除 / 398
13.3.3 锁粗化 / 400
13.3.4 轻量级锁 / 400
13.3.5 偏向锁 / 402
13.4 本章小结 / 403
附  录
附录A 编译Windows版的OpenJDK / 406
附录B 虚拟机字节码指令表 / 414
附录C HotSpot虚拟机主要参数表 / 420
附录D 对象查询语言(OQL)简介 / 424
附录E JDK历史版本轨迹 / 430

---------------------------深入理解Android:Java虚拟机ART---------------------------

推荐序
前言
第1章 本书必读1
1.1 概述1
1.2 准备环境和工具2
1.2.1 准备源代码2
1.2.2 准备Source Insight2
1.2.3 准备模拟器和自制系统镜像5
1.2.4 小结8
1.3 本书的内容9
1.4 本书资源下载说明12
第2章 深入理解Class文件格式13
2.1 Class文件格式总览13
2.2 常量池及相关内容14
2.2.1 常量项的类型和关系14
2.2.2 信息描述规则18
2.2.3 常量池实例剖析19
2.3 field_info和method_info19
2.4 access_flags介绍21
2.5 属性介绍22
2.5.1 属性概貌22
2.5.2 Code属性23
2.5.3 LineNumberTable属性25
2.5.4 LocalVariableTable属性26
2.6 Java指令码介绍27
2.6.1 指令码和助记符27
2.6.2 如何阅读规范28
2.7 学习路线推荐30
2.8 参考资料30
第3章 深入理解Dex文件格式31
3.1 Dex文件格式总览31
3.1.1 Dex和Class文件格式的区别31
3.1.2 Dex文件格式的概貌35
3.2 认识Dex文件36
3.2.1 header_item36
3.2.2 string_id_item等37
3.2.3 class_def38
3.2.4 code_item40
3.3 Dex指令码介绍41
3.3.1 insns的组织形式41
3.3.2 指令码描述规则42
3.4 学习路线推荐44
3.5 参考资料45
第4章 深入理解ELF文件格式46
4.1 概述46
4.2 ELF文件格式介绍46
4.2.1 ELF文件头结构介绍47
4.2.2 Linking View下的ELF52
4.2.3 Execution View下的ELF61
4.2.4 实例分析:调用动态库中的函数65
4.2.5 ELF总结72
4.3 学习路线推荐73
4.4 参考资料73
第5章 认识C++1174
5.1 数据类型76
5.1.1 基本内置数据类型介绍76
5.1.2 指针、引用和void类型77
5.1.3 字符和字符串81
5.1.4 数组82
5.2 C++源码构成及编译83
5.2.1 头文件示例83
5.2.2 源文件示例85
5.2.3 编译86
5.3 Class介绍88
5.3.1 构造、赋值和析构函数89
5.3.2 类的派生和继承97
5.3.3 友元和类的前向声明103
5.3.4 explicit构造函数105
5.3.5 C++中的struct106
5.4 操作符重载106
5.4.1 操作符重载的实现方式107
5.4.2 输出和输入操作符重载108
5.4.3 ->和*操作符重载110
5.4.4 new和delete操作符重载111
5.4.5 函数调用运算符重载117
5.5 函数模板与类模板118
5.5.1 函数模板119
5.5.2 类模板122
5.6 lambda表达式125
5.7 STL介绍127
5.7.1 string类128
5.7.2 容器类129
5.7.3 算法和函数对象介绍134
5.7.4 智能指针类138
5.7.5 探讨STL的学习140
5.8 其他常用知识141
5.8.1 initializer_list141
5.8.2 带作用域的enum141
5.8.3 constexpr142
5.8.4 static_assert143
5.9 参考资料143
第6章 编译dex字节码为机器码145
6.1 编译器全貌介绍147
6.2 编译器前端介绍150
6.2.1 词法分析和lex151
6.2.2 语法分析和yacc160
6.2.3 语义分析和IR生成介绍171
6.3 优化器介绍175
6.3.1 构造CFG176
6.3.2 分析和处理CFG181
6.3.3 数据流分析与SSA191
6.3.4 IR优化204
6.4 ART中的IR—HInstruction222
6.4.1 ART中的IR222
6.4.2 IR之间的关系225
6.4.3 ART IR对象的初始化231
6.5 寄存器分配233
6.5.1 LSRA介绍235
6.5.2 LSRA相关代码介绍247
6.6 机器码生成相关代码介绍271
6.6.1 GenerateFrameEntry272
6.6.2 VisitAdd和VisitInstance-FieldGet273
6.6.3 GenerateSlowPaths275
6.7 总结277
6.8 参考资料280
第7章 虚拟机的创建283
7.1 概述284
7.1.1 JniInvocation Init函数介绍286
7.1.2 AndroidRuntime startVm函数介绍287
7.2 Runtime Create介绍288
7.2.1 Create函数介绍288
7.2.2 Init函数介绍290
7.3 MemMap与OatFileManager293
7.3.1 MemMap介绍293
7.3.2 OatFileManager介绍298
7.4 FaultManager介绍302
7.4.1 信号处理和SignalAction介绍302
7.4.2 FaultManager介绍307
7.5 Thread介绍311
7.5.1 Startup函数介绍311
7.5.2 Attach函数介绍312
7.6 Heap学习之一325
7.6.1 初识Heap中的关键类326
7.6.2 Heap构造函数第一部分337
7.7 JavaVMExt和JNIEnvExt340
7.7.1 JavaVMExt341
7.7.2 JNIEnvExt343
7.7.3 总结344
7.8 ClassLinker345
7.8.1 关键类介绍345
7.8.2 ClassLinker构造函数352
7.8.3 InitFromBootImage353
7.8.4 ClassLinker总结360
7.9 总结和阅读指导362
第8章 虚拟机的启动363
8.1 Runtime Start364
8.2 初识JNI365
8.2.1 JNI中的数据类型365
8.2.2 ScopedObjectAccess等辅助类367
8.2.3 常用JNI函数介绍369
8.3 Jit LoadCompilerLibrary373
8.4 Runtime InitNativeMethods374
8.4.1 JniConstants Init374
8.4.2 RegisterRuntimeNative Methods375
8.4.3 WellKnownClasses Init和LastInit376
8.5 Thread相关376
8.5.1 Runtime InitThreadGroups377
8.5.2 Thread FinishSetup377
8.5.3 Runtime StartDaemonThreads380
8.6 Runtime CreateSystemClassLoader381
8.7 类的加载、链接和初始化383
8.7.1 关键类介绍383
8.7.2 SetupClass392
8.7.3 LoadClass相关函数393
8.7.4 LinkClass相关函数398
8.7.5 DefineClass414
8.7.6 Verify相关函数416
8.7.7 Initialize相关函数424
8.7.8 ClassLinker中其他常用函数426
8.7.9 ClassLoader介绍437
8.8 虚拟机创建和启动关键内容梳理445
第9章 深入理解dex2oat447
9.1 概述448
9.2 ParseArgs介绍452
9.2.1 CompilerOptions类介绍453
9.2.2 ProcessOptions函数介绍454
9.2.3 InsertCompileOptions函数介绍455
9.3 OpenFile介绍456
9.4 Setup介绍458
9.4.1 Setup代码分析之一458
9.4.2 Setup代码分析之二464
9.4.3 Setup代码分析之三474
9.4.4 Setup代码分析之四484
9.5 CompileImage484
9.5.1 Compile485
9.5.2 ArtCompileDEX496
9.5.3 OptimizingCompiler JniCompile499
9.5.4 OptimizingCompiler Compile527
9.6 OAT和ART文件格式介绍544
9.6.1 OAT文件格式544
9.6.2 ART文件格式550
9.6.3 oatdump介绍554
9.7 总结561
第10章 解释执行和JIT562
10.1 基础知识564
10.1.1 LinkCode564
10.1.2 Runtime ArtMethod566
10.1.3 栈和参数传递572
10.2 解释执行580
10.2.1 art_quick_to_interpreter_bridge580
10.2.2 artQuickToInterpreter-Bridge582
10.2.3 EnterInterpreterFromEntry-Point584
10.2.4 调用栈的管理和遍历593
10.3 ART中的JIT599
10.3.1 Jit、JitCodeCache等600
10.3.2 JIT阈值控制与处理609
10.3.3 OSR的处理612
10.4 HDeoptimize的处理615
10.4.1 VisitDeoptimize相关616
10.4.2 QuickExceptionHandler相关618
10.4.3 解释执行中关于Deoptimize的处理621
10.5 Instrumentation介绍623
10.5.1 MethodEnterEvent和MethodExitEvent624
10.5.2 DexPcMovedEvent625
10.6 异常投递和处理625
10.6.1 抛异常626
10.6.2 异常处理629
10.7 总结635
第11章 ART中的JNI636
11.1 JavaVM和JNIEnv637
11.1.1 JavaVMExt相关介绍638
11.1.2 JNIEnvExt介绍642
11.2 Java native方法的调用644
11.2.1 art_jni_dlsym_lookup_stub644
11.2.2 art_quick_generic_jni_trampoline646
11.3 CallStaticVoidMethod651
11.4 JNI中引用型对象的管理653
11.4.1 关键类介绍653
11.4.2 JniMethodStart和JniMethod-End657
11.4.3 IndirectReferenceTable相关函数658
11.4.4 NewObject和jobject的含义660
11.4.5 JNI中引用对象相关662
11.4.6 PushLocalFrame和PopLocalFrame663
11.4.7 回收引用对象664
11.5 总结666
第12章 CheckPoints、线程同步及信号处理668
12.1 CheckPoints介绍669
12.1.1 设置Check Point标志位670
12.1.2 Check Points的设置672
12.1.3 执行检查点处的任务676
12.2 ThreadList和ThreadState681
12.2.1 线程ID683
12.2.2 RunCheckpoint和Dump684
12.2.3 SuspendAll和ResumeAll687
12.2.4 Thread状态切换690
12.3 线程同步相关知识691
12.3.1 关键类介绍692
12.3.2 synchronized的处理697
12.3.3 Object wait、notifyAll等705
12.4 volatile成员的读写707
12.4.1 基础知识707
12.4.2 解释执行模式下的处理711
12.4.3 机器码执行模式的处理712
12.5 信号处理714
12.5.1 zygote进程的处理714
12.5.2 非zygote进程的处理716
12.6 总结719
第13章 内存分配与释放720
13.1 Space等关键类介绍722
13.2 ZygoteSpace723
13.3 BumpPointerSpace和RegionSpace725
13.3.1 BumpPointerSpace726
13.3.2 RegionSpace733
13.4 DlMallocSpace和RosAlloc-Space740
13.4.1 DlMallocSpace741
13.4.2 RosAllocSpace745
13.4.3 rosalloc介绍748
13.5 LargeObjectMapSpace760
13.6 new-instance/array指令的处理762
13.6.1 设置内存分配器762
13.6.2 解释执行模式下的处理767
13.6.3 机器码执行模式下的处理770
13.6.4 Heap AllocObjectWith-Allocator773
13.7 细观Space779
13.7.1 Space类779
13.7.2 ContinuousSpace和Discon-tinuousSpace类781
13.7.3 MemMapSpace和Continuous MemMapAllocSpace类782
13.7.4 MallocSpace类783
13.8 Heap学习之二784
13.8.1 Heap构造函数784
13.8.2 关键类介绍792
13.8.3 ObjectVisitReferences806
13.9 总结812
第14章 ART中的GC813
14.1 GC基础知识814
14.1.1 Mark-Sweep Collection原理介绍815
14.1.2 Copying Collection原理介绍817
14.1.3 Mark-Compact Collection原理介绍818
14.1.4 其他概念819
14.2 Runtime VisitRoots819
14.2.1 关键数据结构821
14.2.2 Thread VisitRoots824
14.3 ART GC概览827
14.3.1 关键数据结构827
14.3.2 ART GC选项830
14.3.3 创建回收器和设置回收策略832
14.4 MarkSweep835
14.4.1 Heap相关成员变量取值情况835
14.4.2 MarkSweep概貌837
14.4.3 MarkingPhase840
14.4.4 PausePhase848
14.4.5 ReclaimPhase851
14.4.6 FinishPhase857
14.4.7 PartialMarkSweep857
14.4.8 StickyMarkSweep858
14.4.9 Concurrent MarkSweep864
14.4.10 Parallel GC868
14.4.11 MarkSweep小结869
14.5 ConcurrentCopying870
14.5.1 InitalizePhase871
14.5.2 FlipThreadRoots873
14.5.3 MarkingPhase881
14.5.4 ReclaimPhase883
14.5.5ConcurrentCopying小结885
14.6 MarkCompact885
14.6.1 MarkingPhase886
14.6.2 ReclaimPhase889
14.6.3 MarkCompact小结891
14.7 SemiSpace892
14.7.1 InitializePhase893
14.7.2 MarkingPhase894
14.7.3 SemiSpace小结898
14.8 Java Reference对象的处理899
14.8.1 基础知识899
14.8.2 MarkSweep中Reference对象的处理903
14.8.3ReferenceProcessor904
14.8.4 PhantomReference的处理912
14.8.5 finalize函数的调用913
14.8.6 Reference处理小结917
14.9 Heap学习之三917
14.9.1 Heap Trim917
14.9.2 CollectGarbageInternal919
14.9.3 PreZygoteFork924
14.9.4 内存碎片的解决926
14.10 总结927
14.11 参考资料928


前言:

---------------------------深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)---------------------------

Java是目前用户最多、使用范围最广的软件开发技术之一。Java的技术体系主要由支撑Java程序运行的虚拟机、提供各开发领域接口支持的Java API、Java编程语言及许多第三方Java框架(如Spring、Struts等)构成。在国内,有关Java API、Java语言语法及第三方框架的技术资料和书籍非常丰富,相比之下,有关Java虚拟机的资料却显得异常贫乏。
这种状况在很大程度上是由Java开发技术本身的一个重要优点导致的:在虚拟机层面隐藏了底层技术的复杂性以及机器与操作系统的差异性。运行程序的物理机器的情况千差万别,而Java虚拟机则在千差万别的物理机上建立了统一的运行平台,实现了在任意一台虚拟机上编译的程序都能在任何一台虚拟机上正常运行。这一极大优势使得Java应用的开发比传统C/C++应用的开发更高效和快捷,程序员可以把主要精力集中在具体业务逻辑上,而不是物理硬件的兼容性上。在一般情况下,一个程序员只要了解了必要的Java API、Java语法,以及学习适当的第三方开发框架,就已经基本能满足日常开发的需要了,虚拟机会在用户不知不觉中完成对硬件平台的兼容及对内存等资源的管理工作。因此,了解虚拟机的运作并不是一般开发人员必须掌握的知识。
然而,凡事都具备两面性。随着Java技术的不断发展,它被应用于越来越多的领域之中。其中一些领域,如电力、金融、通信等,对程序的性能、稳定性和可扩展性方面都有极高的要求。程序很可能在10个人同时使用时完全正常,但是在10?000个人同时使用时就会缓慢、死锁,甚至崩溃。毫无疑问,要满足10?000个人同时使用需要更高性能的物理硬件,但是在绝大多数情况下,提升硬件效能无法等比例地提升程序的运作性能和并发能力,甚至可能对程序运作状况完全没有任何改善。这里面有Java虚拟机的原因:为了达到给所有硬件提供一致的虚拟平台的目的,牺牲了一些与硬件相关的性能特性。更重要的是人为原因:如果开发人员不了解虚拟机一些技术特性的运行原理,就无法写出最适合虚拟机运行和自优化的代码。
其实,目前商用的高性能Java虚拟机都提供了相当多的优化特性和调节手段,用于满足应用程序在实际生产环境中对性能和稳定性的要求。如果只是为了入门学习,让程序在自己的机器上正常运行,那么这些特性可以说是可有可无的;如果用于生产开发,尤其是企业级生产开发,就迫切需要开发人员中至少有一部分人对虚拟机的特性及调节方法具有很清晰的认识,所以在Java开发体系中,对架构师、系统调优师、高级程序员等角色的需求一直都非常大。学习虚拟机中各种自动运作特性的原理也成为了Java程序员成长道路上必然会接触到的一课。本书可以使读者以一种相对轻松的方式学习虚拟机的运作原理,对Java程序员的成长也有较大的帮助。
第2版与第1版的区别
JDK 1.7在2011年7月28日正式发布,相对于2006年发布的JDK 1.6,新版的JDK有了许多新的特性和改进。本书的第2版也相应地进行了修改和升级,把讲解的技术平台从JDK 1.6提升至JDK 1.7。例如,增加了对JDK 1.7中最新的G1收集器,以及JDK 1.7中JSR-292 InvokeDynamic(对非Java语言的调用支持)的分析讲解等内容。
在第1版出版后,笔者收到了许多热心读者的反馈意见,部分读者提出OpenJDK开源已久,第1版却很少有直接分析OpenJDK源码的内容,有点“视宝山而不见”的感觉。因此,在本书第2版中,笔者特别加强了对这部分内容的讲解,其中在第1章中就介绍了如何分析、调试OpenJDK源码等。在本书后续章节中,不少关于功能点的讲解都直接使用OpenJDK中的HotSpot源码或者JIT编译器生成的本地代码作为论据。
如何把Java虚拟机原理中许多理论性很强的知识、特性应用于实践开发,是本书贯穿始终的主旨。由于笔者希望在本书第2版中进一步加强知识的实践性,因此增加了许多对处理JVM常见问题技能的讲解,包括如何分析GC日志、如何分析JIT编译器代码优化过程和生成代码等。并且,在第1版的基础上,第2版中进一步增加了若干处理JVM问题的实践案例供读者参考。
另外,本书第2版还修正了第1版中多处错误的、有歧义的和不完整的描述。有关勘误信息,可以参考第1版的勘误页面(http://icyfenix.iteye.com/blog/1119214)。
本书面向的读者
(1)使用Java技术体系的中、高级开发人员
Java虚拟机作为中、高级开发人员必须修炼的知识,有着较高的学习门槛,本书可作为学习虚拟机的优秀教材。
(2)系统调优师
系统调优师是近几年才兴起的职业,本书中的大量案例、代码和调优实战将会对系统调优师的日常工作有直接的帮助。
(3)系统架构师
保障系统的性能、并发和伸缩等能力是系统架构师的主要职责之一,而这部分与虚拟机的运作密不可分,本书可以作为他们制定应用系统底层框架的参考资料。
如何阅读本书
本书一共分为五个部分:走近Java、自动内存管理机制、虚拟机执行子系统、程序编译与代码优化、高效并发。各部分基本上是互相独立的,没有必然的前后依赖关系,读者可以从任何一个感兴趣的专题开始阅读,但是每个部分中的各个章节间有先后顺序。
本书并没有假设读者在Java领域具备很专业的技术水平,因此在保证逻辑准确的前提下,尽量用通俗的语言和案例讲述虚拟机中与开发的关系最为密切的内容。当然,学习虚拟机技术本身就需要读者有一定的基础,且本书的读者定位是中、高级程序员,因此本书假设读者自己了解一些常用的开发框架、Java API和Java语法等基础知识。
笔者希望读者在阅读本书的同时,把本书中的实践内容亲自验证一遍,其中用到的代码清单可以从华章网站(http://www.hzbook.com)下载。
语言约定
本书在语言和技术上有如下约定:
本书中提到HotSpot、JRockit虚拟机、WebLogic服务器等产品的所有者时,仍然使用Sun和BEA公司的名称,实际上,BEA和Sun分别于2008年和2009年被Oracle公司收购,现在已经不存在这两个商标了,但毫无疑问的是,它们都是在Java领域中做出过卓越贡献的、值得程序员纪念的公司。
JDK从1.5版本开始,在官方的正式文档与宣传资料中已经不再使用类似“JDK 1.5”的名称,只有程序员内部使用的开发版本号(Developer Version,例如java-version的输出)才继续沿用1.5、1.6和1.7的版本号,而公开版本号(Product Version)则改为JDK 5、JDK 6和JDK 7的命名方式,为了行文一致,本书所有场合统一采用开发版本号的命名方式。
由于版面关系,本书中的许多示例代码都没有遵循最优的代码编写风格,如使用的流没有关闭流等,请读者在阅读时注意这一点。
如果没有特殊说明,本书中所有讨论都是以Sun JDK 1.7为技术平台的。不过如果有某个特性在各个版本间的变化较大,一般都会说明它在各个版本间的差异。
内容特色
第一部分 走近Java
本书的第一部分为后文的讲解建立了良好的基础。尽管了解Java技术的来龙去脉,以及编译自己的OpenJDK对于读者理解Java虚拟机并不是必需的,但是这些准备过程可以为走近Java技术和Java虚拟机提供很好的引导。第一部分只有第1章:
第1章 介绍了Java技术体系的过去、现在和未来的一些发展趋势,并介绍了如何独立地编译一个OpenJDK 7。
第二部分 自动内存管理机制
因为程序员把内存控制的权力交给了Java虚拟机,所以可以在编码的时候享受自动内存管理的诸多优势,不过也正是这个原因,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会成为一项异常艰难的工作。第二部分包括第2~5章:
第2章 讲解了虚拟机中内存是如何划分的,以及哪部分区域、什么样的代码和操作可能导致内存溢出异常,并讲解了各个区域出现内存溢出异常的常见原因。
第3章 分析了垃圾收集的算法和JDK 1.7中提供的几款垃圾收集器的特点及运作原理。通过代码实例验证了Java虚拟机中自动内存分配及回收的主要规则。
第4章 介绍了随JDK发布的6个命令行工具与两个可视化的故障处理工具的使用方法。
第5章 与读者分享了几个比较有代表性的实际案例,还准备了一个所有开发人员都能“亲身实战”的练习,读者可通过实践来获得故障处理和调优的经验。
第三部分 虚拟机执行子系统
执行子系统是虚拟机中必不可少的组成部分,了解了虚拟机如何执行程序,才能写出更优秀的代码。第三部分包括第6~9章:
第6章 讲解了Class文件结构中的各个组成部分,以及每个部分的定义、数据结构和使用方法,以实战的方式演示了Class文件的数据是如何存储和访问的。
第7章 介绍了类加载过程的“加载”、“验证”、“准备”、“解析”和“初始化”5个阶段中虚拟机分别执行了哪些动作,还介绍了类加载器的工作原理及其对虚拟机的意义。
第8章 分析了虚拟机在执行代码时如何找到正确的方法,如何执行方法内的字节码,以及执行代码时涉及的内存结构。
第9章 通过4个类加载及执行子系统的案例,分享了使用类加载器和处理字节码的一些值得欣赏和借鉴的思路,并通过一个实战练习来加深对前面理论知识的理解。
第四部分 程序编译与代码优化
Java程序从源码编译成字节码和从字节码编译成本地机器码的这两个过程,合并起来其实就等同于一个传统编译器所执行的编译过程。第四部分包括第10~11章:
第10章 分析了Java语言中泛型、主动装箱和拆箱、条件编译等多种语法糖的前因后果,并通过实战演示了如何使用插入式注解处理器来实现一个检查程序命名规范的编译器插件。
第11章 讲解了虚拟机的热点探测方法、HotSpot的即时编译器、编译触发条件,以及如何从虚拟机外部观察和分析JIT编译的数据和结果,此外,还讲解了几种常见的编译优化技术。
第五部分 高效并发
Java语言和虚拟机提供了原生的、完善的多线程支持,这使得它天生就适合开发多线程并发的应用程序。不过我们不能期望系统来完成所有并发相关的处理,了解并发的内幕也是成为一个高级程序员不可缺少的课程。第五部分包括第12~13章:
第12章 讲解了虚拟机Java内存模型的结构及操作,以及原子性、可见性和有序性在Java内存模型中的体现,介绍了先行发生原则的规则及使用,还了解了线程在Java语言中是如何实现的。
第13章 介绍了线程安全涉及的概念和分类、同步实现的方式及虚拟机的底层运作原理,并且介绍了虚拟机实现高效并发所采取的一系列锁优化措施。
参考资料
本书名为“深入理解Java虚拟机”,但要想深入理解虚拟机,仅凭一本书肯定是远远不够的,读者可以通过以下信息找到更多关于Java虚拟机方面的资料。我在写作此书的时候,也从下面这些参考资料中获得了很大的帮助。
(1)书籍
《The Java Virtual Machine Specification,Java SE 7 Edition》
要学习虚拟机,无论如何都必须掌握“Java虚拟机规范”。这本书的概念和细节描述与Sun的早期虚拟机(Sun Classic VM)高度吻合,不过,随着技术的发展,高性能虚拟机真正的细节实现方式已经渐渐与虚拟机规范所描述的差距越来越大,如果只能选择一本参考书来了解虚拟机,那我推荐这本书。此书的Java SE 7版在2011年7月出版发行,这是自1999年发布的《Java虚拟机规范(第2版)》以来的第一次版本更新。笔者对Java SE 7版的全文进行了翻译,并与原书一样在网上免费发布了全文PDF。
《The Java Language Specification,Java SE 7 Edition》
虽然虚拟机并不是Java语言专有的,但是了解Java语言的各种细节规定对理解虚拟机的行为也是很有帮助的,它与上一本《Java虚拟机规范》都是Sun官方出品的书籍,而且这本书还是由Java之父James Gosling亲自执笔撰写的。这本书也与《Java虚拟机规范》一样,可以在官方网站完全免费下载到全文PDF,但暂时没有中文译本,《Java语言规范(第3版)》于2005年7月由机械工业出版社引进出版。
《Oracle JRockit The Definitive Guide》
《Oracle JRockit权威指南》,2010年7月出版,国内也没有(可能是尚未)引进这本书,它是由JRockit的两位资深开发人员(其中一位还是JRockit Mission Control团队的TeamLeader)撰写的JRockit虚拟机高级使用指南。虽然JRockit的用户量可能不如HotSpot多,但也是目前最流行的三大商业虚拟机之一,并且不同虚拟机中的很多实现思路都是可以对比参照的。这本书是了解现代高性能虚拟机很好的参考资料。
《Inside the Java 2 Virtual Machine,Second Edition》
《深入Java虚拟机(第2版)》,2000年1月出版,2003年由机械工业出版社出版其中文译本。在相当长的时间里,这本书是唯一的一本关于Java虚拟机的中文图书。
《Java Performance》
《Java Performance》是“The Java”系列(许多人都读过该系列中最出名的《Effective Java》)图书中最新的一本,2011年10月出版,暂时没有中文版。这本书并非全部都围绕Java虚拟机(只有第3、4、7章直接与Java虚拟机相关),而是从操作系统到基于Java的上层程序性能度量和调优的全面介绍,其中涉及Java虚拟机的内容具备一定的深度和可实践性。
(2)网站资源
高级语言虚拟机圈子:http://hllvm.group.iteye.com/
里面有一些国内关于虚拟机的讨论,并不只限于JVM,而是涉及对所有的高级语言虚拟机(High-Level Language Virtual Machine)的讨论,但该网站建立在ITEye上,自然还是以讨论Java虚拟机为主。圈主RednaxelaFX(莫枢)的博客(http://rednaxelafx.iteye.com/)是另外一个非常有价值的虚拟机及编译原理等资料的分享园地。
HotSpot Internals:https://wikis.oracle.com/display/HotSpotInternals/Home
一个关于OpenJDK的Wiki网站,许多文章都由JDK的开发团队编写,更新较慢,但是仍然有很高的参考价值。
The HotSpot Group:http://openjdk.java.net/groups/hotspot/
HotSpot组群,包含虚拟机开发、编译器、垃圾收集和运行时4个邮件组,其中有关于HotSpot虚拟机的最新讨论。
勘误和支持
在本书交稿的时候,我并不像想象中的那样兴奋或放松,写作之时那种“战战兢兢、如履薄冰”的感觉依然萦绕在心头。在每一章、每一节落笔之时,我都在考虑如何才能把各个知识点更有条理地讲述出来,同时也在担心会不会由于自己理解有偏差而误导了读者。由于写作水平和写作时间所限,书中难免存在不妥之处,所以特地开通了一个读者邮箱(understandingjvm@gmail.com)与大家交流,大家如有任何意见或建议欢迎与我联系。相信写书与写程序一样,作品一定都是不完美的,因为不完美,我们才有不断追求完美的动力。
本书第2版的勘误,将会在作者的博客(http://icyfenix.iteye.com/)中发布。欢迎读者在博客上留言。
致谢
首先要感谢我的家人,在本书写作期间全靠他们对我的悉心照顾,才让我能够全身心地投入到写作之中,而无后顾之忧。
同时要感谢我的工作单位远光软件,公司为我提供了宝贵的工作、学习和实践的环境,书中的许多知识点都来自于工作中的实践;也感谢与我一起工作的同事们,非常荣幸能与你们一起在这个富有激情的团队中共同奋斗。
还要感谢Oracle公司虚拟机团队的莫枢,在百忙之中抽空审阅了本书,提出了许多宝贵的建议和意见。
最后,感谢机械工业出版社华章公司的编辑,本书能够顺利出版离不开他们的敬业精神和一丝不苟的工作态度。
周志明

---------------------------深入理解Android:Java虚拟机ART---------------------------

本书主要内容及特色
本书是笔者“深入理解Android”系列的第四本。本书将关注Android系统中至关重要的部分—Java虚拟机ART。市面上介绍Java虚拟机的书籍非常多,但鲜少有书籍能从虚拟机源代码出发对其进行详细分析。随着Android设备的大规模普及,ART虚拟机已经成为当今使用最为广泛的JVM之一。所以,对ART虚拟机进行研究有着非同寻常的意义。本书的出现在一定程度上填补了这方面的空白。
本书的主要内容概述如下:
第1章介绍ART虚拟机学习前需要准备好的工具、环境等。
第2章介绍Class文件的格式及内容。
第3章介绍Android中Dex文件的格式。
第4章介绍ELF文件格式。
第5章介绍C++11相关的、能帮助读者阅读ART源码的必备知识。
第6章以编译原理为基础,介绍ART虚拟机编译相关的知识。
第7章以ART Runtime对象的创建为主线,介绍主要的模块及一些关键类、数据结构等知识。
第8章以ART Runtime的Start为主线进行分析,覆盖的内容包括相关模块的启动、类的解析、加载、链接、初始化等。
第9章介绍dex字节码转机器码的核心进程dex2oat以及.oat和.art文件格式。
第10章介绍虚拟机的解释执行和JIT部分以及异常的投递和处理的过程。
第11章介绍JNI在ART虚拟机的实现。
第12章介绍虚拟机Java线程执行相关的知识,包括线程暂停和恢复运行、synchronized、Object wait/notify的实现、volatile变量的读写处理等。
第13章介绍内存分配和释放相关的知识。包括ART虚拟机中的各种Space类型、new指令的实现以及ART虚拟机中Heap模块的部分内容。
第14章介绍和垃圾回收有关的基础知识以及相关垃圾回收器,还有Java Reference的处理以及Heap模块的部分内容。
本书通过理论和代码相结合的方式进行讲解,旨在引领读者一步步了解Android系统中JVM的工作原理。
读者对象
Android系统开发工程师
系统开发工程师常常需要深入理解Android平台上各个系统的运转过程。本书所涉及的Java虚拟机是从事相关工作的读者在工作和学习中最想了解的。
Android应用开发工程师
Android应用开发工程师所开发的程序是运行在JVM中的。如果能更深入地了解JVM的实现将极大帮助开发工程师写出更高质量的程序。
对JVM感兴趣的在校高年级本科生、研究生等研究人员
JVM的理论书籍非常多,但很少有从分析源代码的角度来介绍其工作原理的。这本理论与代码实现深度结合的书籍一定可在该领域助相关研究人员一臂之力。
如何阅读本书
本书是一本有一定深度的书籍,所以读者在阅读时:
请务必首先阅读第1章。后续如果碰到阅读上的困难,可能还需时常回顾第1章。
本书的内容是经过笔者精心编排的,如果读者不是很有把握的话,建议严格按照顺序阅读。
本书的某些章节涉及了笔者在撰写它们时所参考的资料。这些资料较多,读者可根据它们开展进一步的研究工作。
另外,和笔者之前出版的《深入理解Android》卷Ⅰ以及卷Ⅱ类似的是:本书在每章开头都把本章涉及的源码路径全部列出,而在具体分析源码时,则只列出该源码的文件名及所分析的函数或相关数据结构名。例如:
[AndroidRuntime.cpp->AndroidRuntime::start]
//这里是源码分析和一些注释
最后,本书在描述类之间的关系及函数调用流程上,使用了UML的静态类图及序列图。UML是一个强大的工具,但它的建模规范过于繁琐,为更简单清晰地描述事情的本质,本书并未完全遵循UML的建模规范。这里仅举两例,如图1和图2所示。
在图1中:
外部类内部的方框用于表示内部类。另外,外部类A、内部类B也用于表示内部类。
接口和普通类用同一种框图表示。
图2所示为本书描述数据结构时使用的UML图。
图1 UML示例图之一
图2 UML示例图之二
图2为本书描述数据结构及成员时使用的UML图例。
特别注意 本书使用的UML图都比较简单,读者不必花费大量时间专门学习UML。另外,出于方便考虑,本书所绘制的UML图没有严格遵守UML规范。这一点敬请读者谅解。
本书涉及的Android源码及一些开发工具的下载可通过笔者的博客blog.csdn.net/innost首页置顶文章“深入理解Android系列书籍资源分享更新”查看。关于它们的使用详情,请读者阅读本书第1章了解。
勘误和支持
由于作者的水平有限,加之编写时间仓促,书中难免会出现一些错误或不准确的地方,恳请读者不吝赐教。若有问题,可通过邮件或在博客上留言与笔者共同商讨。笔者的联系方式如下:
邮箱fanping.deng@gmail.com
博客blog.csdn.net/innost
致谢
本书的顺利出版首先要感谢杨福川编辑的大力支持。另外,要感谢张锡鹏编辑在审稿期间严谨负责的工作。
另外,笔者需要特别感谢现就职的民生银行总行信息科技部。这是笔者第一次供职于一家金融企业。在此工作的这段时间里,我深刻体会到了民生科技人勇于开拓、锐意创新的精神气质,同时也感受到“金融科技为银行创造价值”的深远意义和重大责任。在此,笔者借助本书对相关领导和同事表示衷心的感谢。他们是牛新庄、毛斌、李建兵、林冠峰、李彧、娄丽明、侯佳腾、常薇、王连诚、张梦涵、侯超、金西银、孙升芸、孟凡娇、文静、赖穆彬等。正是你们的鼓励、支持和信任才使我的业余研究成果得以成书。
当然,本书能快速出版,还需要感谢几位功力深厚并热心参与技术审稿的专家。他们是滴滴出行资深研发工程师孙鹏飞和赵旭阳、高通无线半导体技术有限公司资深工程师钟长庚。几位专家在各自领域所体现出来的专业素养和技术水平之高时刻提醒笔者应牢记“路漫漫其修远兮,吾将上下而求索”。另外,其他几位小伙伴罗迪、段启智、高建武、陈永志也对本书的编写提供了不小的帮助。在此一并感谢他们。
最后,一如既往地感谢家人和妻子。另外,特别感谢索菲娅小朋友,正是她不厌其烦地问“爸爸,你为什么看电脑呀”,才使得笔者不得不加快编写速度。最后,感谢所有花费宝贵时间和精力关注本书的读者以及所有在人生和职业道路上曾给予我指导的诸位师长。
邓凡平
北京

媒体评论:

---------------------------深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)---------------------------

Java程序是如何运行的?Java虚拟机在其中扮演了怎样的角色?如何让Java程序具有更高的并发性?许多Java程序员都会有诸如此类的疑问。无奈,国内在很长一段时间里都没有一本从实际应用的角度讲解Java虚拟机的著作,本书的出版可谓填补了这个空白。它从Java程序员的角度出发,系统地将Java程序运行过程中涉及的各种知识整合到一起,并配以日常工作中可能会碰到的疑难案例,引领读者轻松踏上探索Java虚拟机的旅途,是对Java虚拟机感兴趣的广大读者的福音!——莫枢(RednaxelaFX)Oracle HotSpot VM编译器团队工程师

---------------------------深入理解Android:Java虚拟机ART---------------------------

随着Android设备的大规模普及,ART虚拟机已经成为当今世上使用最为广泛的JVM之一。对ART虚拟机的研究有着非同寻常的意义,而本书则在一定程度上填补了这方面的空白。它对ART虚拟机的架构设计和实现原理进行了细致入微的分析,不仅对Android工程师学习ART虚拟机有帮助,也对Java工程师学习JVM有极大的价值。
—— 毛斌 民生银行总行信息科技部副总经理
从2011年至今,凡平对整个Android系统的源代码进行了反复阅读和剖析,代码多达百万行,在此基础上出版专著4本,对Android领域的贡献巨大。这次,他向Android Java虚拟机ART发起挑战,历时近3年,完成了这部近1000页的巨著,一如既往地保持了过去的高水准!
—— 周志明 远光软件研究院院长、《深入理解Java虚拟机》《智慧的疆界》作者
我在研发Android热修复框架时遇到方法调用地址错乱、类型转换错误、补丁不生效等很多疑难杂症,解决这些难题需要对底层虚拟机有深入了解,但苦于相关资料匮乏,一直有很多困惑没有解开。本书对Android ART虚拟机源码进行分析,对混合编译器dex2oat、解释器、JIT、多线程管理以及垃圾回收等虚拟机核心技术进行了深入讲解,读完后令我豁然开朗,知其所以然。
—— 赵旭阳 滴滴出行资深研发工程师/滴滴Android热修复负责人/本书审稿专家
性能监控方面的数据采集、分析需要了解底层原理,比如oat的文件结构、Java方法的执行、JIT的原理和触发时机、线程如何切换状态、异常信号处理、堆和栈产生OOM的原理、GC触发时机和几种GC模式的执行原理、内存的分配和管理、异常的投递等,这些都是我们在做性能优化的过程中持续关注的地方。之前只关注了Java虚拟机的局部内容,本书做了一个完整的解析,可以帮助我们掌握JVM的执行原理,了解问题的本质。
—— 孙鹏飞 滴滴出行资深研发工程师/本书审稿专家
本书通过源码深入和系统地分析了Android Java虚拟机ART的Class文件、dex文件、 dex2oat、JIT、多线程同步、内存分配和回收等关键组件的实现原理。内容翔实、重点突出,大幅降低了学习ART的难度。我在工作中遇到的ART的疑难问题都能在本书中找到答案。应用开发工程师深入理解后,可以开发出更加高质量、高性能和高稳定性的应用;系统工程师阅读后,可以优化ART虚拟机并且解决它的稳定性修复等疑难问题。
—— 钟长庚 高通无线半导体技术有限公司资深工程师/本书审稿专家

书摘:

---------------------------深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)---------------------------

第一部分
走近Java
第1章 走近Java
第1章 走近Java
世界上并没有完美的程序,但我们并不因此而沮丧,因为写程序本来就是一个不断追求完美的过程。
1.1 概述
Java不仅仅是一门编程语言,还是一个由一系列计算机软件和规范形成的技术体系,这个技术体系提供了完整的用于软件开发和跨平台部署的支持环境,并广泛应用于嵌入式系统、移动终端、企业服务器、大型机等各种场合,如图1-1所示。时至今日,Java技术体系已经吸引了900多万软件开发者,这是全球最大的软件开发团队。使用Java的设备多达几十亿台,其中包括11亿多台个人计算机、30亿部移动电话及其他手持设备、数量众多的智能卡,以及大量机顶盒、导航系统和其他设备。
Java能获得如此广泛的认可,除了它拥有一门结构严谨、面向对象的编程语言之外,还有许多不可忽视的优点:它摆脱了硬件平台的束缚,实现了“一次编写,到处运行”的理想;它提供了一个相对安全的内存管理和访问机制,避免了绝大部分的内存泄露和指针越界问题;它实现了热点代码检测和运行时编译及优化,这使得Java应用能随着运行时间的增加而获得更高的性能;它有一套完善的应用程序接口,还有无数来自商业机构和开源社区的第三方类库来帮助它实现各种各样的功能……Java所带来的这些好处使程序的开发效率得到了很大的提升。作为一名Java程序员,在编写程序时除了尽情发挥Java的各种优势外,还应该去了解和思考一下Java技术体系中这些技术特性是如何实现的。认识这些技术运作的本质,是自己思考“程序这样写好不好”的基础和前提。当我们在使用一种技术时,如果不再依赖书本和他人就能得到这些问题的答案,那才算上升到了“不惑”的境界。
本书将与读者一起分析Java技术中最重要的那些特性的实现原理。在本章中,我们将重点介绍Java技术体系内容以及Java的历史、现在和未来的发展趋势。
1.2 Java技术体系
从广义上讲,Clojure、JRuby、Groovy等运行于Java虚拟机上的语言及其相关的程序都属于Java技术体系中的一员。如果仅从传统意义上来看,Sun官方所定义的Java技术体系包括以下几个组成部分:
?Java程序设计语言
?各种硬件平台上的Java虚拟机
?Class文件格式
?Java API类库
?来自商业机构和开源社区的第三方Java类库
我们可以把Java程序设计语言、Java虚拟机、Java API类库这三部分统称为JDK(Java Development
Kit),JDK是用于支持Java程序开发的最小环境,在后面的内容中,为了讲解方便,有一些地方会以JDK来代替整个Java技术体系。另外,可以把Java
API类库中的Java SE API子集和Java虚拟机这两部分统称为JRE(Java Runtime
Environment),JRE是支持Java程序运行的标准环境。图1-2展示了Java技术体系所包含的内容,以及JDK和JRE所涵盖的范围。
以上是根据各个组成部分的功能来进行划分的,如果按照技术所服务的领域来划分,或者说按照Java技术关注的重点业务领域来划分,Java技术体系可以分为4个平台,分别为:
?Java Card:支持一些Java小程序(Applets)运行在小内存设备(如智能卡)上的平台。
?Java ME(Micro Edition):支持Java程序运行在移动终端(手机、PDA)上的平台,对Java
API有所精简,并加入了针对移动终端的支持,这个版本以前称为J2ME。
?Java SE(Standard
Edition):支持面向桌面级应用(如Windows下的应用程序)的Java平台,提供了完整的Java核心API,这个版本以前称为J2SE。
?Java EE(Enterprise
Edition):支持使用多层架构的企业应用(如ERP、CRM应用)的Java平台,除了提供Java SE
API外,还对其做了大量的扩充并提供了相关的部署支持,这个版本以前称为J2EE。
1.3 Java发展史
从第一个Java版本诞生到现在已经有18年的时间了。沧海桑田一瞬间,转眼18年过去了,在图1-3所展示的时间线中,我们看到JDK已经发展到了1.7版。在这18年里还诞生了无数和Java相关的产品、技术和标准。现在让我们走入时间隧道,从孕育Java语言的时代开始,再来回顾一下Java的发展轨迹和历史变迁。
1991年4月,由James Gosling博士领导的绿色计划(Green
Project)开始启动,此计划的目的是开发一种能够在各种消费性电子产品(如机顶盒、冰箱、收音机等)上运行的程序架构。这个计划的产品就是Java语言的前身:Oak(橡树)。Oak当时在消费品市场上并不算成功,但随着1995年互联网潮流的兴起,Oak迅速找到了最适合自己发展的市场定位并蜕变成为Java语言。
1995年5月23日,Oak语言改名为Java,并且在SunWorld大会上正式发布Java
1.0版本。Java语言第一次提出了“Write Once,Run Anywhere”的口号。
1996年1月23日,JDK 1.0发布,Java语言有了第一个正式版本的运行环境。JDK
1.0提供了一个纯解释执行的Java虚拟机实现(Sun Classic VM)。JDK
1.0版本的代表技术包括:Java虚拟机、Applet、AWT等。
1996年4月,10个最主要的操作系统供应商申明将在其产品中嵌入Java技术。同年9月,已有大约8.3万个网页应用了Java技术来制作。在1996年5月底,Sun公司于美国旧金山举行了首届JavaOne大会,从此JavaOne成为全世界数百万Java语言开发者每年一度的技术盛会。
1997年2月19日,Sun公司发布了JDK 1.1,Java技术的一些最基础的支撑点(如JDBC等)都是在JDK
1.1版本中发布的,JDK
1.1版的技术代表有:JAR文件格式、JDBC、JavaBeans、RMI。Java语法也有了一定的发展,如内部类(Inner
Class)和反射(Reflection)都是在这个时候出现的。
直到1999年4月8日,JDK
1.1一共发布了1.1.0~1.1.8九个版本。从1.1.4之后,每个JDK版本都有一个自己的名字(工程代号),分别为:JDK
1.1.4 - Sparkler(宝石)、JDK 1.1.5 - Pumpkin(南瓜)、JDK 1.1.6 -
Abigail(阿比盖尔,女子名)、JDK 1.1.7 - Brutus(布鲁图,古罗马政治家和将军)和JDK 1.1.8
Chelsea(切尔西,城市名)。
1998年12月4日,JDK迎来了一个里程碑式的版本JDK
1.2,工程代号为Playground(竞技场),Sun在这个版本中把Java技术体系拆分为3个方向,分别是面向桌面应用开发的J2SE(Java
2 Platform, Standard Edition)、面向企业级开发的J2EE(Java 2 Platform,
Enterprise Edition)和面向手机等移动终端开发的J2ME(Java 2 Platform, Micro
Edition)。在这个版本中出现的代表性技术非常多,如EJB、Java Plug-in、Java
IDL、Swing等,并且这个版本中Java虚拟机第一次内置了JIT(Just In Time)编译器(JDK
1.2中曾并存过3个虚拟机,Classic VM、HotSpot VM和Exact VM,其中Exact
VM只在Solaris平台出现过;后面两个虚拟机都是内置JIT编译器的,而之前版本所带的Classic
VM只能以外挂的形式使用JIT编译器)。在语言和API级别上,Java添加了strictfp关键字与现在Java编码之中极为常用的一系列Collections集合类。在1999年3月和7月,分别有JDK
1.2.1和JDK 1.2.2两个小版本发布。
1999年4月27日,HotSpot虚拟机发布,HotSpot最初由一家名为“Longview
Technologies”的小公司开发,因为HotSpot的优异表现,这家公司在1997年被Sun公司收购了。HotSpot虚拟机发布时是作为JDK
1.2的附加程序提供的,后来它成为了JDK 1.3及之后所有版本的Sun JDK的默认虚拟机。
2000年5月8日,工程代号为Kestrel(美洲红隼)的JDK 1.3发布,JDK 1.3相对于JDK
1.2的改进主要表现在一些类库上(如数学运算和新的Timer API等),JNDI服务从JDK
1.3开始被作为一项平台级服务提供(以前JNDI仅仅是一项扩展),使用CORBA
IIOP来实现RMI的通信协议,等等。这个版本还对Java 2D做了很多改进,提供了大量新的Java 2D
API,并且新添加了JavaSound类库。JDK 1.3有1个修正版本JDK
1.3.1,工程代号为Ladybird(瓢虫),于2001年5月17日发布。
自从JDK
1.3开始,Sun维持了一个习惯:大约每隔两年发布一个JDK的主版本,以动物命名,期间发布的各个修正版本则以昆虫作为工程名称。
2002年2月13日,JDK 1.4发布,工程代号为Merlin(灰背隼)。JDK
1.4是Java真正走向成熟的一个版本,Compaq、Fujitsu、SAS、Symbian、IBM等著名公司都有参与甚至实现自己独立的JDK
1.4。哪怕是在十多年后的今天,仍然有许多主流应用(Spring、Hibernate、Struts等)能直接运行在JDK
1.4之上,或者继续发布能运行在JDK 1.4上的版本。JDK
1.4同样发布了很多新的技术特性,如正则表达式、异常链、NIO、日志类、XML解析器和XSLT转换器等。JDK
1.4有两个后续修正版:2002年9月16日发布的工程代号为Grasshopper(蚱蜢)的JDK
1.4.1与2003年6月26日发布的工程代号为Mantis(螳螂)的JDK 1.4.2。
2002年前后还发生了一件与Java没有直接关系,但事实上对Java的发展进程影响很大的事件,那就是微软公司的.NET
Framework发布了。这个无论是技术实现上还是目标用户上都与Java有很多相近之处的技术平台给Java带来了很多讨论、比较和竞争,.NET平台和Java平台之间声势浩大的孰优孰劣的论战到目前为止都在继续。
2004年9月30日,JDK 1.5发布,工程代号Tiger(老虎)。从JDK
1.2以来,Java在语法层面上的变换一直很小,而JDK
1.5在Java语法易用性上做出了非常大的改进。例如,自动装箱、泛型、动态注解、枚举、可变长参数、遍历循环(foreach循环)等语法特性都是在JDK
1.5中加入的。在虚拟机和API层面上,这个版本改进了Java的内存模型(Java Memory
Model,JMM)、提供了java.util.concurrent并发包等。另外,JDK 1.5是官方声明可以支持Windows
9x平台的最后一个JDK版本。
2006年12月11日,JDK 1.6发布,工程代号Mustang(野马)。在这个版本中,Sun终结了从JDK
1.2开始已经有8年历史的J2EE、J2SE、J2ME的命名方式,启用Java SE 6、Java EE 6、Java ME
6的命名方式。JDK 1.6的改进包括:提供动态语言支持(通过内置Mozilla JavaScript
Rhino引擎实现)、提供编译API和微型HTTP服务器API等。同时,这个版本对Java虚拟机内部做了大量改进,包括锁与同步、垃圾收集、类加载等方面的算法都有相当多的改动。
在2006年11月13日的JavaOne大会上,Sun公司宣布最终会将Java开源,并在随后的一年多时间内,陆续将JDK的各个部分在GPL
v2(GNU General Public License
v2)协议下公开了源码,并建立了OpenJDK组织对这些源码进行独立管理。除了极少量的产权代码(Encumbered
Code,这部分代码大多是Sun本身也无权限进行开源处理的)外,OpenJDK几乎包括了Sun
JDK的全部代码,OpenJDK的质量主管曾经表示,在JDK 1.7中,Sun
JDK和OpenJDK除了代码文件头的版权注释之外,代码基本上完全一样,所以OpenJDK 7与Sun JDK
1.7本质上就是同一套代码库开发的产品。
JDK
1.6发布以后,由于代码复杂性的增加、JDK开源、开发JavaFX、经济危机及Sun收购案等原因,Sun在JDK发展以外的事情上耗费了很多资源,JDK的更新没有再维持两年发布一个主版本的发展速度。JDK
1.6到目前为止一共发布了37个Update版本,最新的版本为Java SE 6 Update
37,于2012年10月16日发布。
2009年2月19日,工程代号为Dolphin(海豚)的JDK 1.7完成了其第一个里程碑版本。根据JDK
1.7的功能规划,一共设置了10个里程碑。最后一个里程碑版本原计划于2010年9月9日结束,但由于各种原因,JDK
1.7最终无法按计划完成。
从JDK
1.7最开始的功能规划来看,它本应是一个包含许多重要改进的JDK版本,其中的Lambda项目(Lambda表达式、函数式编程)、Jigsaw项目(虚拟机模块化支持)、动态语言支持、GarbageFirst收集器和Coin项目(语言细节进化)等子项目对于Java业界都会产生深远的影响。在JDK
1.7开发期间,Sun公司由于相继在技术竞争和商业竞争中都陷入泥潭,公司的股票市值跌至仅有高峰时期的3%,已无力推动JDK
1.7的研发工作按正常计划进行。为了尽快结束JDK
1.7长期“跳票”的问题,Oracle公司收购Sun公司后不久便宣布将实行“B计划”,大幅裁剪了JDK 1.7预定目标,以便保证JDK
1.7的正式版能够于2011年7月28日准时发布。“B计划”把不能按时完成的Lambda项目、Jigsaw项目和Coin项目的部分改进延迟到JDK
1.8之中。最终,JDK
1.7的主要改进包括:提供新的G1收集器(G1在发布时依然处于Experimental状态,直至2012年4月的Update
4中才正式“转正”)、加强对非Java语言的调用支持(JSR-292,这项特性到目前为止依然没有完全实现定型)、升级类加载架构等。
到目前为止,JDK 1.7已经发布了9个Update版本,最新的Java SE 7 Update
9于2012年10月16日发布。从Java SE 7 Update 4起,Oracle开始支持Mac OS
X操作系统,并在Update 6中达到完全支持的程度,同时,在Update
6中还对ARM指令集架构提供了支持。至此,官方提供的JDK可以运行于Windows(不含Windows
9x)、Linux、Solaris和Mac OS平台上,支持ARM、x86、x64和Sparc指令集架构类型。
2009年4月20日,Oracle公司宣布正式以74亿美元的价格收购Sun公司,Java商标从此正式归Oracle所有(Java语言本身并不属于哪间公司所有,它由JCP组织进行管理,尽管JCP主要是由Sun公司或者说Oracle公司所领导的)。由于此前Oracle公司已经收购了另外一家大型的中间件企业BEA公司,在完成对Sun公司的收购之后,Oracle公司分别从BEA和Sun中取得了目前三大商业虚拟机的其中两个:JRockit和HotSpot,Oracle公司宣布在未来1~2年的时间内,将把这两个优秀的虚拟机互相取长补短,最终合二为一。可以预见在不久的将来,Java虚拟机技术将会产生相当巨大的变化。
根据Oracle官方提供的信息,JDK 1.8的第一个正式版本将于2013年9月发布,JDK 1.8将会提供在JDK
1.7中规划过,但最终未能在JDK
1.7中发布的特性,即Lambda表达式、Jigsaw(很不幸,随后Oracle公司又宣布Jigsaw在JDK
1.8中依然无法完成,需要延至JDK 1.9)和JDK 1.7中未实现的一部分Coin等。
在2011年的JavaOne大会上,Oracle公司还提到了JDK
1.9的长远规划,希望未来的Java虚拟机能够管理数以GB计的Java堆,能够更高效地与本地代码集成,并且令Java虚拟机运行时尽可能少人工干预,能够自动调节。
1.4 Java虚拟机发展史
上一节我们从整个Java技术的角度观察了Java技术的发展,许多Java程序员都会潜意识地把它与Sun公司的HotSpot虚拟机等同看待,也许还有一些程序员会注意到BEA
JRockit和IBM J9,但对JVM的认识不仅仅只有这些。
从1996年初Sun公司发布的JDK 1.0中所包含的Sun Classic
VM到今天,曾经涌现、湮灭过许多或经典或优秀或有特色的虚拟机实现,在这一节中,我们先暂且把代码与技术放下,一起来回顾一下Java虚拟机家族的发展轨迹和历史变迁。
1.4.1 Sun Classic / Exact VM
以今天的视角来看,Sun Classic
VM的技术可能很原始,这款虚拟机的使命也早已终结。但仅凭它“世界上第一款商用Java虚拟机”的头衔,就足够有让历史记住它的理由。
1996年1月23日,Sun公司发布JDK
1.0,Java语言首次拥有了商用的正式运行环境,这个JDK中所带的虚拟机就是Classic
VM。这款虚拟机只能使用纯解释器方式来执行Java代码,如果要使用JIT编译器,就必须进行外挂。但是假如外挂了JIT编译器,JIT编译器就完全接管了虚拟机的执行系统,解释器便不再工作了。用户在这款虚拟机上执行java
-version命令,将会看到类似下面这行输出:
java version "1.2.2"
Classic VM (build JDK-1.2.2-001, green threads, sunwjit)
其中的“sunwjit”就是Sun提供的外挂编译器,其他类似的外挂编译器还有Symantec
JIT和shuJIT等。由于解释器和编译器不能配合工作,这就意味着如果要使用编译器执行,编译器就不得不对每一个方法、每一行代码都进行编译,而无论它们执行的频率是否具有编译的价值。基于程序响应时间的压力,这些编译器根本不敢应用编译耗时稍高的优化技术,因此这个阶段的虚拟机即使用了JIT编译器输出本地代码,执行效率也和传统的C/C++程序有很大差距,“Java语言很慢”的形象就是在这时候开始在用户心中树立起来的