前言
Java语言已经走过了20多年的历程。在此期间,尽管新语言层出不穷,但它们并未动摇Java的地位。也许历史选择了Java,或者Java改变了历史。简而言之,Java无疑是一种成功的编程语言。这种语言的成功归功于高性能语言虚拟机热点。
客观地说,hotspot虚拟机是目前顶级语言虚拟机之一。其模板解释器是语言解释器的最终状态。除非有重大的技术突破和方法改变,否则很难超越。它的垃圾收集器也在日益改进。新的不间断GC的出现标志着JVM正在向GC的顶级俱乐部迈进。在权衡了编译开销和应用程序吞吐量之后,它的实时编译器是一件出色的艺术品。
本文既考虑到内容的广度也关注了技术的深度,详细描述了虚拟机的底层实现,并与上层Java语言或者库结合,以实用为目标展开介绍,同时还讨论了它们的深刻意义。
从内容广度的角度看,本文除了讨论耳熟能详的Java虚拟机技术外,还详细讨论了业界最新的通用虚拟机平台Graal VM、CDS/AppCDS/DynamicCDS、Instrumentation库、编译重放、非标准字节码、栈上替换,RTM锁、JIT编译器IR、JIT编译器可视化工具、编译逃离、EpsilonGC/ShenandoahGC/ZGC、G1字符串去重等技术。
从内容深度的角度看,本文详细讨论了:
-
G1 GC的回收策略和底层代码实现;
-
C1编译器的HIR和LIR,以及针对不同IR上应用的优化;
-
C2编译器的Ideal Graph以及平台无关的优化技术;
-
CPU重排序与ObjectMonitor、Mutex的底层实现;
-
模板解释器的代码片段生成逻辑和字节码模板生成逻辑;
目录
主要内容
本文共11章,全文从逻辑上可分为运行时、编译器、垃圾回收器三个部分。
第一部分(第1~6章),介绍Java虚拟机运行时的相关知识;
第1章Java大观园;作为本书的开篇,本章将围绕Java的生态系统,简单介绍JDK、JVM、JEP,引导读者走进虚拟机的世界。
1.1节介绍了各具特色的JDK分支和OpenJDK的子项目。1.2节介绍了Java改进提案,它们代表类Java社区最新的工作动向。1.3节简单描述了历史长河中存在或者曾经存在的Java虚拟机。1.4节讨论了HotSpotVM的组件、源码结构、构建、调试以及修改代码后如何回归测试。最后1.5节展望未来,讨论了Java的前沿技术Graal VM。
第2章类可用机制;一个类需要经过漫长的旅程才能被虚拟机其他组件,如解释器、编译器、GC等在运行时使用,下面将详细介绍类的一个完整生命周期,即加载、链接、初始化三部曲。
本章从2.1节开始,介绍了位于磁盘的二进制表示的字节码被类文件解析器加载并解析,得到虚拟机内部用于表示类的InstanceKlass数据结构。为了保证字节码是安全可靠的,在2.2节链接阶段,首先验证了字节码的结构正确性;出于性能考虑,链接阶段还可能调用重写器将一些字节码替换为高性能的版本,加快后面的解释执行;链接阶段的核心工作是设置编译器/解释器入口以便后续代码能够正常执行,同时为了保障后续解释/编译模式的切换,还会设置适配器来消除两种模式之间的沟壑。接着,根据《Java虚拟机规范》中赋予类初始化的语义,在2.3节介绍了初始化阶段同时执行用户的静态代码块和隐式静态字段初始化。最后2.4节特别讨论了类的重定义。
第3章对象和类;本章讨论Java对象和类在HotSpot VM内部的具体实现,探索虚拟机在底层是如何对这些Java语言的概念建模的。
本章主要围绕对象和类的相关内容展开。3.1节介绍了HotSpot VM中对象和类的设计原则。3.2节介绍了对象和类模型,它们在JVM层表示Java层的对象。3.3节介绍了类模型,它们在JVM层表示Java层的Class<?>。对象和类共同构成对象类二分模型,是HotSpot VM的核心数据结构。
第4章运行时;运行时,顾名思义是指虚拟机运行的时候,它表征程序执行时的状态,本章将讨论虚拟机运行时涉及的方方面面。
4.1节讨论了JVM中五花八门的线程以及它们的作用。4.2节从源码角度分析线程API的实现,同时扩展分析线程API实现时涉及的其他重要模块如JavaCalls、os,并简单提及ParkEvent、Parker、OrderAccess组件。4.3节讨论了线程栈帧的实现。4.4节讨论虚拟机层的代码如何与Java层的代码交互,以此引出JNI和JavaCalls模块。4.5节讨论JDK中的Unsafe类,并给出它在虚拟机的具体实现。
第5章模板解释器;最简单的Java虚拟机可以只包括类加载器和解释器:类加载器加载字节码iconst_1、iconst_1、iadd并传给虚拟机,解释器按照字节码计算并得到结果。在没有JIT编译器的情况下,解释器从某种程度上来说就是虚拟机本体,有关虚拟机的绝大部分问题都能在解释器中找到答案。本章将详细讨论解释器的内部构造和解释执行过程。
本章讨论了HotSpot VM中最重要组件之一——解释器的构成和工作机制。5.1节讨论解释器的源码结构和构成解释器的基础设施;5.2节讨论了构成解释器的元素;5.3节和5.4节描述了解释器与其他虚拟机组件的合作方式;5.5节详细讨论了解释器实现,包括解释器如何执行普通Java方法和native方法、标准字节码是如何实现的,以及非标准字节码是如何实现的。
第6章并发设施;并发是Java的一大特色,通过并发,可以在Java层实现多个线程协同工作或者互斥执行。上层应用的易用性、安全性、高效性都是由HotSpot VM中的并发设施来保证的。并发设施是HotSpot VM中相当复杂的组件,本章将简单讨论虚拟机在并发方面付出的努力。
6.1节介绍了重排序和内存屏障,它们是Java内存模型的基础。6.2节简单介绍了Java内存模型,它在程序的一些特定的地方设置内存屏障,禁止指令重排序的发生,使程序顺序和执行顺序保持一致。6.3节介绍了虚拟机内部并发基础设施,包括原子操作、ParkEvent、Parker、Monitor,它们广泛用于虚拟机内部的各种需要同步的地方。6.4节介绍了更高层次的基于并发继承设施的锁优化策略。
第二部分(第7~9章),介绍编译基础知识和虚拟机的两个即时编译器;
第7章编译概述;编译器是一个相对复杂且专业的领域,需要一些先验理论知识。本章将简单讨论编译理论的基本概念,也会逐一讨论HotSpot VM本身涉及的许多特设的编译技术,为后面的篇章打下理论基础。
本章简单介绍了虚拟机涉及的编译技术。7.1节介绍了即时编译器依赖的运行时代码生成技术,然后分门别类地介绍了HotSpot VM的各类编译器。7.2节介绍HotSpot VM特设的编译技术,它们和虚拟机运行时紧密相连。为了理解后面两章,7.3节介绍了一些编译术语的基本概念,读者如果在后面两章遇到疑问,可以回顾本节的内容。最后7.4节介绍了编译器的调试方法和调试工具,便于读者深入理解即时编译器的行为。
第8章C1编译器;C1使用经典的基于静态单赋值的两层图IR作为HIR:第一层为控制流图,用于处理控制流;第二层为基本块,用于处理数据流。C1的HIR同时含有控制流和数据流,是学习编译原理的良好实例,本章将详细讨论C1编译器(后面简称C1)。
8.1节描述了解释器到C1编译器的调用栈以及C1编译的主要流程,即字节码到HIR,再到LIR,最后生成机器代码的过程。其中,8.2节描述了字节码到HIR的实现。8.3节描述了C1中比较复杂的代码优化过程,基本涵盖了HIR的所有优化操作。8.4节描述了从HIR到LIR的生成过程,由于LIR到机器代码大部分是线性映射过程,所以不再赘述。
第9章C2编译器;C2编译器即Op to Compiler,又叫Server Compiler,它的定位与C1相反:C1面向客户端程序,需要快速响应用户请求;C2面向长期运行的服务端程序,它允许在编译上花更多时间,以此换取程序峰值执行性能。本章将详细讨论大名鼎鼎的C2编译器(后面简称C2)。
9.1节简单概括了C2的编译流程,并简要介绍了C2的核心数据结构理想图。9.2节描述了编译流程的开始,即理想图的构造过程。9.3节描述了编译流程的中间优化步骤。最后9.4节简单介绍了编译流程的后面部分,也就是核心的代码生成过程。
第三部分(第10~11章),介绍各种垃圾回收器并深入分析G1GC。
第10章垃圾回收;垃圾回收是JDK开发者社区最活跃的主题,在-XX:+RunReallyFast虚拟机参数没有到来之前,了解垃圾回收运行机制和工作原理对于Java开发者是很有必要的。本章将从最简单的垃圾回收器开始,逐个介绍垃圾回收器的原理和底层实现。
本章根据历史时间线介绍了HotSpot VM现存的所有垃圾回收器。10.1节简单讨论虚拟机与垃圾回收器交互的机制。10.2节介绍了SerialGC,它使用单线程清理垃圾。10.3节的Parallel GC解决了Serial GC的不足,使用多线程清理垃圾。10.4节的CMS GC部分解决了Parallel GC的不足,除了多线程清理垃圾外,还允许清理垃圾过程中Mutator线程继续运行。10.5节的G1GC解决了CMS GC的不足,将堆划分为Region,回收过程中整理Region,消除碎片化。10.6节的Shenandoah GC解决了G1 GC的不足,它的回收停顿时间不会随着堆变大而增长,同时允许对象复制阶段Mutator线程继续工作。10.7和10.8节的ZGC与Shenandoah GC同属于新一代的低延时垃圾回收器,它们的目标STW时间均小于10ms,且不会随着堆的增大而变长。最后对所有垃圾回收器做了简单总结。
第11章G1GC;G1 GC是面向服务端应用程序的垃圾回收器,通过新的堆设计和停顿预测模型,可以到达用户指定的一个比较合理的软实时目标。本章将详细分析G1 GC的设计和实现。
11.1节简单介绍了G1的基本概念及其垃圾回收策略。11.2节详细讨论了YGC。11.3节重点讨论了G1独有的Mixed GC,具体回收过程可分为全局并发标记和对象复制过程。其中,全局并发标记选择收益较高的对象,对象复制借用YGC的代码将对象复制到新的Region,然后清理原来的Region。11.4节简单讨论了FGC,在YGC或者FGC过程中G1可以可选地执行字符串去重操作。11.5节以YGC为例介绍了G1字符串去重。
点赞收藏查看主页来获取!
本文适合的读者对象
本文适合那些希望在Java语言方面有进一步提升的开发者,也适合任何对JVM底层感兴趣且想要一探究竟的开发者。
同时,对编译器或垃圾回收器感兴趣的读者也能从中受益。