首页 > 其他分享 >HotSpot逃逸分析

HotSpot逃逸分析

时间:2024-05-26 10:04:27浏览次数:27  
标签:分析 阈值 CompileThreshold 代码 OSR HotSpot 编译 XX 逃逸

JIT即时编译

即时编译(Just-In-Time Compilation, JIT)是一种强大的技术,旨在增强基于字节码的语言(如Java、.NET)的运行时性能。它的工作原理是在程序运行过程中动态地将频繁执行的字节码转换成本地机器码,从而大幅提高执行效率。这一过程克服了纯解释执行的性能瓶颈,同时保留了跨平台的灵活性。

HotSpot虚拟机的JIT实现

HotSpot是Java虚拟机的一个著名实现,它通过三种主要的即时编译器来平衡启动时间和运行时性能:

  • C1编译器(Client Compiler):设计用于快速启动和较小的内存占用,牺牲了一定的优化程度以换取更快的编译速度。适用于对启动时间敏感的应用场景。

  • C2编译器(Server Compiler):专注于代码的深度优化,尽管编译速度较慢,但能够产生高度优化的机器码,适合长时间运行且对运行时性能要求极高的服务端应用。

  • C1+C2混合模式(分层编译,Tiered Compilation):结合了C1和C2的优点,程序启动初期使用C1快速编译以加速启动,随着代码“热点”(即频繁执行的代码块)的识别,这些热点代码会被C2重新编译,以达到最佳的运行时性能。在Java 8之前,默认不启用分层编译,需手动添加-server -XX:+TieredCompilation参数开启。

逃逸分析及其优化

逃逸分析是JIT编译器中的一个高级特性,它分析对象的生命周期和作用域,判断对象是否“逃逸”出其创建的方法或线程,以此来决定是否可以采取进一步的优化措施。逃逸的两种情况包括:

  • 方法逃逸:对象被作为参数传递给其他方法,其引用超出创建方法的范畴。
  • 线程逃逸:对象被赋予了全局变量或类变量,有可能被其他线程访问。

当分析得知对象未发生逃逸时,可以执行以下优化:

  • 同步消除:如果确定一个对象不会被多线程访问,那么针对该对象的同步操作(如加锁解锁)可以安全地被消除,减少不必要的性能开销。
  • 标量替换:将对象拆解成若干个单独的变量(标量)直接存储在栈上,避免堆分配,提高访问速度和垃圾回收效率 通过-XX:+EliminateAllocations可以开启标量替换,-XX:+PrintEliminateAllocations查看。
  • 栈上分配:对于生命周期短且未逃逸的对象,直接在栈上分配内存,而非堆上,栈的分配速度快于堆,且对象生命周期结束时自动释放内存,减少了GC负担。

分层编译和逃逸分析在1.8中是默认是开启的

编译阈值与OSR编译解析

在即时编译(JIT)的背景下,编译阈值是一个关键参数,它决定了代码从解释执行过渡到编译执行的时机。这一机制确保了程序在频繁执行的“热点”代码上投资编译资源,以最大化性能提升,同时避免了对不常执行代码的过度优化,减少启动时间和内存占用。

标准编译阈值
  • Client与Server编译器的默认阈值:如前所述,HotSpot JVM中的Client编译器(C1)默认将编译阈值设为1500次方法调用或回边(循环)计数,而Server编译器(C2)则更为保守,将阈值设为10000次。这意味着在默认情况下,一个方法或循环必须被执行足够的次数后,才会被JVM认为是“热点”并进行编译优化。

  • 调整CompileThreshold参数:通过JVM启动参数-XX:CompileThreshold=<value>,用户可以根据具体应用的需求调整这个阈值。减小该值可以让编译发生得更早,有助于快速提升性能,但可能会增加启动时间和内存使用;增大则相反,适用于那些启动时间敏感但运行时间较长的应用。

OSR(On Stack Replacement)编译
  • 概念:OSR编译是即时编译技术中的一种特殊形式,旨在优化长时间运行的循环或方法体内部的代码,即使整个方法本身执行次数不多。它通过在方法栈帧上直接替换正在执行的字节码为优化后的本地代码,无需等待整个方法达到标准编译阈值。

  • 触发阈值:OSR编译的触发条件相对复杂,不仅仅取决于执行次数,还与循环体内代码的复杂度、循环次数等因素相关。虽然没有直接的固定阈值供用户直接设置,但可以通过JVM参数间接影响,如-XX:OnStackReplacePercentage=<percentage>,这个参数指定了执行OSR编译的循环回边计数占标准编译阈值的比例。例如,若设置为93%,则当一个循环执行次数达到标准编译阈值的93%时,将会触发OSR编译。

  • 公式估算:虽然具体的OSR阈值计算涉及JVM内部机制,不易直接给出一个通用公式,但大致思路是根据方法的实际运行情况(如循环次数)与上述百分比计算一个大致的触发点。理解OSR编译的核心在于认识到它是对特定代码段(通常是循环)的针对性优化,而非整个方法。

-XX:CompileThreshold = 10000
-XX:OnStackReplacePercentage = 140
-XX:InterpreterProfilePercentage = 33
OSR trigger = (CompileThreshold * (OnStackReplacePercentage -
InterpreterProfilePercentage)) / 100 = 10700

其中trigger即为OSR编译的阈值。
那么如果把CompileThreshold设置适当小一点,是不是可以提早触发编译行为,减少在堆上生成User
对象?我们可以进行通过不同参数验证一下:

  • 1、 -XX:CompileThreshold = 5000 ,结果如下:在这里插入图片描述
  • 2、 -XX:CompileThreshold = 2500 ,结果如下:
  • 在这里插入图片描述
  • 3、 -XX:CompileThreshold = 2000 ,结果如下:
    在这里插入图片描述
  • 4、 -XX:CompileThreshold = 1500 ,结果如下:
    在这里插入图片描述
    在我的机器中,当设置到1500时,在堆上生成的User对象反而升到4w个,目前还不清楚原因是啥…
    JIT编译在默认情况是异步进行的,当触发某方法或某代码块的优化时,先将其放入编译队列,然后由编
    译线程进行编译,编译之后的代码放在CodeCache中,CodeCache的大小也是有限的,通过 -XX:-
    BackgroundCompilation 参数可以关闭异步编译,我们可以通过执行 java -cp . -Xmx3G -Xmn2G -
    server -XX:CompileThreshold=1 -XX:-TieredCompilation -XX:-BackgroundCompilation JVM 命
    令看看同步编译的效果:在java堆上只生成了2个对象。
    在这里插入图片描述
    1、热点代码的编译过程是有成本的,如果逻辑复杂,编程成本更高;
    2、编译后的代码会被存放在有大小限制的CodeCache中,如果CompileThreshold设置的太低,JIT会
    将一大堆执行不那么频繁的代码进行编译,并放入CodeCache,导致之后真正执行频繁的代码没有足够
    的空间存放;

标签:分析,阈值,CompileThreshold,代码,OSR,HotSpot,编译,XX,逃逸
From: https://blog.csdn.net/qq_38420688/article/details/139114861

相关文章

  • 【阻抗建模、验证扫频法】光伏并网逆变器扫频与稳定性分析(包含锁相环电流环)(Simulink
    ......
  • 人工智能+跨癌种分析,能否解决医学数据样本量小的问题?【医学AI|顶刊速递|05-26】
    小罗碎碎念先说明,目前小罗只是硕士,以下个人观点很有可能不准确,欢迎批评指正!!小罗虚心听取有益建议!!众所周知,医学数据相比于其他领域的数据来说,属于小样本数据。那么从工科角度出发,模型的预测效果要想更精准,那么数据量就要尽可能大。好的,既然要解决的问题已经明确了,那么怎......
  • 【信息安全】Web 网络安全纵观与前景分析
    Web网络安全纵观与前景分析在此之前,欢迎关注波比网络培训、环境、资料、考证波比网络官方公众号:blbinet波比网络工作室官方公众号:blbistudio获取技术支持访问:https://www.blbi.cn/form/1/select技能大赛各赛项交流群:https://www.blbi.cn/threads/40/更多正式......
  • U-Boot Makefile分析
    当我们拿到开发板以后,是有三种uboot的,这三种uboot的区别如表所示:U-Boot初次编译首先在Ubuntu中安装ncurses库,否则编译会报错:sudoapt-getinstalllibncurses5-dev将正点原子提供的uboot-imx-2016.03-2.1.0-ge468cdc-v1.5.tar.bz2拷贝到自己建的文件夹下,并进行解压......
  • 空气质量与车流量的相关性分析
    空气质量与车流量对应指标的相关性分析目录空气质量与车流量对应指标的相关性分析数据预处理处理目标代码实现相关系数表两两变量关系图相关系数热力图相关系数聚类图相关程度较高的关系呈现数据预处理1.当天空气质量/车流量其中一类全部缺失/均缺失的占整体数据的不到5%,这部分......
  • 【初探Java之路 六 】集合1-ArrayList和LinkedList的使用与源码分析
    ......
  • Go语言中局部变量的逃逸分析(从汇编的角度)
    Go语言中局部变量的逃逸分析(从汇编的角度)正常情况下,局部变量是存储在栈中的,如果将局部变量的地址当作函数值返回,这势必会导致悬挂指针的错误,因为函数返回后,函数的栈帧就会被回收,返回的局部变量地址自然就访问不到了。但是Go语言会进行逃逸分析,编译器如果遇到这种情况,就会将......
  • Pandas合并操作——《Python数据分析库Pandas》
    Pandas合并操作——《Python数据分析库Pandas》Pandas合并操作使用`merge`方法进行数据合并使用`concat`方法进行数据堆叠使用`join`方法进行列连接`merge`方法的更多选项`concat`方法的轴参数`join`方法与`merge`方法的比较性能考虑总结Pandas合并操......
  • 【编译原理】LL(1)预测分析法
    一、实验目的LL(1)的含义:第一个L表明自顶向下分析是从左向右扫描输入串,第2个L表明分析过程中将使用最左推导,1表明只需向右看一个符号便可决定如何推导,即选择哪个产生式进行推导。LL(1)预测分析方法是确定的自顶向下的语法分析技术。本次实验的主要目的就是要加深对LL(1)预测......
  • Pandas连接操作——《Python数据分析库Pandas》
    Pandas连接操作——《Python数据分析库Pandas》Pandas连接操作内连接(InnerJoin)左连接(LeftJoin)右连接(RightJoin)外连接(OuterJoin)总结Pandas连接操作Pandas是一个强大的Python数据分析库,它提供了丰富的数据结构和数据操作工具,使得数据处理变得简单......