Java 性能调优实战
刘超
前金山软件技术经理
59174 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 49 讲
开篇词 (1讲)
模块一 · 概述 (2讲)
结束语 (1讲)
Java 性能调优实战
15
15
1.0x
00:00/00:00
登录|注册

22 | 深入JVM即时编译器JIT,优化Java编译

标量替换
锁消除
栈上分配
逃逸分析
方法内联
回边计数器
方法调用计数器
C2编译器
C1编译器
<clinit>方法
解析
准备
验证
方法区
类加载器
方法表集合
常量池
Graal编译器
AOT编译器
编译优化技术
热点探测
即时编译器类型
类初始化
类连接
类加载
类编译
思考题
总结
即时编译
类编译加载执行过程
深入JVM即时编译器JIT,优化Java编译

该思维导图由 AI 生成,仅供参考

你好,我是刘超。
说到编译,我猜你一定会想到 .java 文件被编译成 .class 文件的过程,这个编译我们一般称为前端编译。Java 的编译和运行过程非常复杂,除了前端编译,还有运行时编译。由于机器无法直接运行 Java 生成的字节码,所以在运行时,JIT 或解释器会将字节码转换成机器码,这个过程就叫运行时编译。
类文件在运行时被进一步编译,它们可以变成高度优化的机器代码,由于 C/C++ 编译器的所有优化都是在编译期间完成的,运行期间的性能监控仅作为基础的优化措施则无法进行,例如,调用频率预测、分支频率预测、裁剪未被选择的分支等,而 Java 在运行时的再次编译,就可以进行基础的优化措施。因此,JIT 编译器可以说是 JVM 中运行时编译最重要的部分之一。
然而许多 Java 开发人员对 JIT 编译器的了解并不多,不深挖其工作原理,也不深究如何检测应用程序的即时编译情况,线上发生问题后很难做到从容应对。今天我们就来学习运行时编译如何实现对 Java 代码的优化。

类编译加载执行过程

在这之前,我们先了解下 Java 从编译到运行的整个过程,为后面的学习打下基础。请看下图:

类编译

在编写好代码之后,我们需要将 .java 文件编译成 .class 文件,才能在虚拟机上正常运行代码。文件的编译通常是由 JDK 中自带的 Javac 工具完成,一个简单的 .java 文件,我们可以通过 javac 命令来生成 .class 文件。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

JVM即时编译器JIT对Java代码进行优化是Java运行时编译的重要组成部分。文章详细介绍了Java代码从编译到运行的整个过程,包括类加载、连接和初始化,以及即时编译器的优化过程。在HotSpot虚拟机中,内置了两个JIT,分别为C1编译器和C2编译器,并介绍了分层编译的优势。热点探测是JIT优化的条件,基于计数器的热点探测会触发JIT编译。文章还涉及了方法内联和逃逸分析等优化手段,以及在Java8和Java9中的编译器变化。总的来说,本文详实介绍了JVM即时编译器JIT对Java代码优化的过程和原理,对于理解Java代码的运行和性能优化具有重要参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Java 性能调优实战》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(32)

  • 最新
  • 精选
  • nightmare
    Class•forName有重载方法可以指定是否需要初始化,而默认的方法初始化设置为true这会初始化类执行链接和初始化操作,而ClasaLoader是有类加载器的loadClass方法加载,传入的是false只会执行链接操作,而不会执行初始化操作

    作者回复: 回答非常详细

    2019-07-11
    3
    50
  • QQ怪
    看老师这篇分享花了1个小时,分享的干货很多,回答下老师的问题: 不同点: 1)Class.forName()除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块,还会执行给静态变量赋值的静态方法。 2)classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。

    作者回复: 这次内容确实有点多,慢慢消化。

    2019-07-12
    2
    29
  • -W.LI-
    这其实是因为由于 HotSpot 虚拟机目前的实现导致栈上分配实现比较复杂。 栈上分配影响: 1.java只有值传递,跨方法的局部变量在栈上分配的话,在现有栈实现上会影响栈的回收。 2.栈属于线程所有,实现栈上分配,会消耗更多的内存。让java的多线程更吃内存。 3.如果实现栈上分配,还需要GC作用会弱化很多吧。 4.基类型栈上分配+引用类型堆分配->全栈上分配。这么实现的话hotspot感觉全推翻了。 老师好有理解的不对的请指出谢谢

    作者回复: W.LI同学解释的很透彻,赞一个。

    2019-07-13
    2
    15
  • 天天向上
    文中讲到:逃逸分析如果发现一个对象只在方法中使用,就会将对象分配在栈上。然而我们的程序大多数对象都是只在方法中使用的啊,那栈就得需要很大的空间了啊??

    作者回复: 使用方法时间非常短,所以在栈上的数据也就很快被释放掉了

    2019-12-29
    3
  • 天信
    很困惑线上服务的时候如何去调整这些参数达到最优解,比如调整 ComplieThrehold 大小或者其它参数,以及调整后到如何计算收益呢

    作者回复: 一般情况下我们不会去调整这些参数,JVM默认值就已经可以满足大多数服务了,使用默认值即可。

    2020-01-07
    2
    2
  • SDL
    差了很多文章 还是没能找到在哪设置这些参数呢 望老师告知一下小白

    作者回复: springboot jar启动文件下,在启动时设置JVM参数就好了,java -xx(jvm参数)-jar xxx.jar

    2019-09-25
    2
  • 尔冬橙
    老师,Javap反编译的内容是生成class文件的中间过程么(在变成二进制文件前的汇编)

    作者回复: class文件是字节码,再JIT 或解释器会将字节码转换成机器码

    2020-03-04
    2
    1
  • Liam
    栈上分配这里,对局部变量对象的大小是否有要求,毕竟栈的内存比较小

    作者回复: 目前hotspot虚拟机暂时不支持栈上分配对象。

    2019-07-11
    1
  • 我又不乱来
    Class.forName加载类的时候会对类进行初始化,如静态代码块,ClassLoader 不会做初始化。spring做类加载的时候应该用的是ClassLoader把。超哥。

    作者回复: 正确

    2019-07-11
    1
  • 尔冬橙
    在非线程安全的情况下,尽量不要使用线程安全容器?这句话是不是线程安全的情况下?

    作者回复: 是非线程安全,有时候非线程安全使用线程安全容器反而增加了性能开销

    2019-09-02
    3
收起评论
显示
设置
留言
32
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部