深入拆解Java虚拟机
郑雨迪
Oracle 高级研究员,计算机博士
立即订阅
28017 人已学习
课程目录
已完结 39 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么我们要学习Java虚拟机?
免费
模块一:Java虚拟机基本原理 (12讲)
01 | Java代码是怎么运行的?
02 | Java的基本类型
03 | Java虚拟机是如何加载Java类的?
04 | JVM是如何执行方法调用的?(上)
05 | JVM是如何执行方法调用的?(下)
06 | JVM是如何处理异常的?
07 | JVM是如何实现反射的?
08 | JVM是怎么实现invokedynamic的?(上)
09 | JVM是怎么实现invokedynamic的?(下)
10 | Java对象的内存布局
11 | 垃圾回收(上)
12 | 垃圾回收(下)
模块二:高效编译 (12讲)
【工具篇】 常用工具介绍
13 | Java内存模型
14 | Java虚拟机是怎么实现synchronized的?
15 | Java语法糖与Java编译器
16 | 即时编译(上)
17 | 即时编译(下)
18 | 即时编译器的中间表达形式
19 | Java字节码(基础篇)
20 | 方法内联(上)
21 | 方法内联(下)
22 | HotSpot虚拟机的intrinsic
23 | 逃逸分析
模块三:代码优化 (10讲)
24 | 字段访问相关优化
25 | 循环优化
26 | 向量化
27 | 注解处理器
28 | 基准测试框架JMH(上)
29 | 基准测试框架JMH(下)
30 | Java虚拟机的监控及诊断工具(命令行篇)
31 | Java虚拟机的监控及诊断工具(GUI篇)
32 | JNI的运行机制
33 | Java Agent与字节码注入
模块四:黑科技 (3讲)
34 | Graal:用Java编译Java
35 | Truffle:语言实现框架
36 | SubstrateVM:AOT编译框架
尾声 (1讲)
尾声 | 道阻且长,努力加餐
深入拆解Java虚拟机
登录|注册

16 | 即时编译(上)

郑雨迪 2018-08-27
在专栏的第一篇中,我曾经简单地介绍过即时编译。这是一项用来提升应用程序运行效率的技术。通常而言,代码会先被 Java 虚拟机解释执行,之后反复执行的热点代码则会被即时编译成为机器码,直接运行在底层硬件之上。
今天我们便来详细剖析一下 Java 虚拟机中的即时编译。

分层编译模式

HotSpot 虚拟机包含多个即时编译器 C1、C2 和 Graal。
其中,Graal 是一个实验性质的即时编译器,可以通过参数 -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler 启用,并且替换 C2。
在 Java 7 以前,我们需要根据程序的特性选择对应的即时编译器。对于执行时间较短的,或者对启动性能有要求的程序,我们采用编译效率较快的 C1,对应参数 -client。
对于执行时间较长的,或者对峰值性能有要求的程序,我们采用生成代码执行效率较快的 C2,对应参数 -server。
Java 7 引入了分层编译(对应参数 -XX:+TieredCompilation)的概念,综合了 C1 的启动性能优势和 C2 的峰值性能优势。
分层编译将 Java 虚拟机的执行状态分为了五个层次。为了方便阐述,我用“C1 代码”来指代由 C1 生成的机器码,“C2 代码”来指代由 C2 生成的机器码。五个层级分别是:
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《深入拆解Java虚拟机》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(23)

  • godtrue
    有点费解,不过还好又明白了一些东西,小结如下:
    1:即时编译-直接将Java字节码编译成机器码,运行在底层硬件之上,这么玩是为了提高代码的执行效率,通俗点就是能使代码跑的更快一些

    2:即时编译的触发点是热点代码,即 即时编译仅针对热点代码来触发,热点代码是通过方法的调用次数或者回边循环的次数来标示的,这里也侧面反映出来即时编译是针对方法块的,有个疑问❓为什么不把所有代码都即时编译一下呢?这样程序的执行效率不是更快吗?为什么还分热点非热点呢?

    3:分层编译的设计也有点奇怪,为什么要这样呢?使用最快的编译代码编译器编译的代码不是更好吗?

    4:解释执行-将Java字节码一段一段的编译成机器码在底层硬件上运行,即时编译是一个相对解释执行而言的概念,它将热点代码先编译成机器码缓存起来,在解释执行字节码的时候判断出已经缓存起来了就不在编译直接获取执行就可以了

    作者回复: 2. 即时编译是以方法为单位的。动态编译比较耗时,如果花了大量CPU资源编译出来的机器码运行不了几次,就很浪费了。

    3. 机器码越快,需要的编译时间就越长。分层编译是一种折衷的方式,既能够满足部分不那么热的代码能够在短时间内编译完成,也能满足很热的代码能够拥有最好的优化。

    2018-08-28
    18
  • 槛外人
    为什么一块代码会被2层编译后还会被3、4层编译?不能某一层编译就完了吗?

    作者回复: 其中一个原因是快速地收集profile,所以会用2 3层编译后的代码,既能够高效运行,也能够收集最终用来4层编译的profile

    2018-11-06
    2
  • 泰格杨
    去优化是啥意思?

    作者回复: 就是从执行机器码切换回解释执行,下一篇会详细介绍。

    2018-08-27
    2
  • 逆流的鱼
    疑问:即时编译之后的机器码和 native 方法是不是可以等同,这样是不是他俩都是占用jvm的内存和线程资源,而具体的Java程序只是持有机器码方法和native方法的引用,具体Java程序的线程调用时也是再委托给JVM 执行
    2018-11-22
    1
  • Leon Wong
    小结一下:

    分层编译的引入是为了让即时编译更具备灵性,使得虚拟机可以根据量化的实际情况以及相应的算法动态选择执行代码的编译路径。分层编译是否开启,决定了编译器的执行阈值是否动态化。

    根据两种不同的计数器(方法调用计数器和循环回边的执行次数计数器),虚拟机有不同的考量,基于方法层面的优化,会使用方法调用计数器作为主要依据,而基于循环层面的,则使用循环回边计数器作为主要依据。

    由此引入了OSR技术,即一种能够替换正在运行函数的栈帧的技术。其目的在于能让执行引擎能在不同的优化层次间来回切换,并以更细粒度(循环)的形式实现之。为了平衡启动性能与峰值性能,OSR可以实现低层次优化往高层次优化的迁移;为了去优化以及方便获取调试信息,OSR可以实现高层次优化往低层次迁移。
    2018-09-18
    1
  • 大场镇车王
    请问带所有profiling是什么意思 所有是个什么概念

    作者回复: 下篇会讲。主要有分支跳转指令的branch profile,和类型相关指令的type profile。

    2018-08-27
    1
  • 郑杰
    能说下及时编译的结果是什么样的吗,然后他是怎么跟解释执行一起运行的

    作者回复: 编译结果就是二进制码,下一篇有具体示例。解释执行遇到方法调用时,JVM会判断目标方法是否被编译。如果是,就跳转至编译好的二进制码中。

    2018-08-27
    1
  • longslee
    老师你好,请教个问题:有个同事写的程序本身占用JVM空间非常大,然后启动项 JAVA8 指定了 -server ,但是运行一段时间后,就会出现 “C2 编译器 什么空间不足,ReservedCodeCacheSize 什么什么”,按照提示调大以后还是会出现。
    2019-11-16
  • leo
    解释执行后的机器码不会缓存吗,为什么之后还需要即时编译
    2019-10-03
  • neohope
    老师您好,在文章最后,我的理解是,从c1或c2到解释运行时,会有内存回收。
    我想问下,当从c1升级到c2后,也会出现“made zombie”将c1代码回收的情况吗?
    此外,是不是解释运行的代码,永远都不会被回收呢?
    谢谢!
    2019-08-28
  • Eric
    为什么执行效率1层大于2层,2层大于3层???
    2019-05-26
  • 我已经设置了昵称
    还是有点不懂,即时编译是在程序运行的时候触发?解释编译是指我们普通的java文件被编译class文件的内容?
    2019-04-11
  • 未知
    每次看都有收获。第三遍。
    2019-03-23
  • 哇!怎么这么大个
    老师,-XX:+PrintCompilation看到的信息都是及时编译的结果吗,还是说包含了及时编译(C1 C2)和解释编译的结果,有没其他查看代码里即时编译的其他相关文档
    2018-12-14
  • Geek_987169
    老师,问下,中止状态是什么意思?

    作者回复: 这里的上下文是在讲编译层次吧?指的是到了1层或者4层之后,就不再就同一个方法触发新的编译请求,除非是OSR编译或者已被去优化

    2018-10-20
  • 夜行观星
    看了分层,还看封面,老师真的用心
    2018-10-01
  • vick
    请教两个问题:
    1. 解释执行如果发现该方法还没有被编译,是否就是触发即时编译生成二进制码去执行?
    2. 一个方法被即时编译成二进制码后,程序运行期间是否就可以无限循环利用之前编译的机器码去执行了,会有需要再重新编译的情况吗?
    2018-09-26
  • Leon Wong
    有个小问题,1、4层是终止(接受)状态的前提是,您的五层应该从0开始,到4层结束,但是您现在1层开始,5层结束,那么终止状态应该是2层和5层。

    作者回复: 对的,我原稿里是从0开始,可能MD语法给识别错了。

    2018-09-17
  • code-artist
    ”前面提到,Java 虚拟机在 0 层、2 层和 3 层执行状态时进行 profiling”
    第0层是解释执行,前面没说带profiling啊? 前面只列出第2,3层带profiling. 这里会不会笔误?

    作者回复: 多谢指出!

    解释执行是带profiling的。最开始列2 3层时明确标注带profiling,是为了区分1,2,3层。

    2018-08-30
  • Desire
    请问打印出!表示什么意思 n表示native

    作者回复: 是否包含异常处理器

    2018-08-28
收起评论
23
返回
顶部