《剑指JVM》——第11章——热点代码探测确定何时JIT——执行引擎4

🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。

✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!

🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客

🔥温馨提示:划到文末发现专栏彩蛋   点击这里直接传送

🔥本篇概览:详细讲解了热点代码探测确定何时JIT,介绍了两种情况——方法常调用、大量循环。并介绍了处理这两种情况的方法——方法调用计数器、回边计数器🌈⭕🔥


【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】


🔥 《剑指JVM》序言-CSDN博客

🔥 《剑指JVM》全书-CSDN博客


🌈章节引出

前一篇章:《剑指JVM》——第11章——为什么HotSpot VM同时存在JIT编译器和解释器——执行引擎3-CSDN博客

🌈章节速览


热点代码探测确定何时JIT

那些需要被编译为本地代码的字节码也被称为“热点代码”,JT编译器在运行时会针对那些频繁被调用的“热点代码”做出深度优化,将其直接编译为对应平台的机器码,以此提升 Java 程序的执行性能。一个被多次调用的方法,或者是一个方法体内部循环次数较多的循环体都可以被称为“热点代码”,因此都可以通过 ЛT编译器编译为机器码,并缓存起来。

1.多次调用的方法


一个方法被多次调用的时候,从解释执行切换到编译执行是在两次方法调用之间产生的(非阻塞)因为上一次方法在被调用的时候还没有将该方法编译好,所以仍然需要继续解释执行,而不需要去等待程序被编译,否则太浪费时间了,等再次调用该方法的时候,发现该方法已经被编译好,那么就会使用编译好的机器码执行。

2.大量循环的代码

还有一种情况就是一个方法体内包含大量的循环的代码,比如下面的代码

public class Main {
    public static void main(String[] args) {
        for (int i = 0; i < 20000; i++) {
            System.out.println(i);
        }
    }
}

main()方法被执行的次数只有一次,但是方法体内部有一个循环 20000次的循环体,这种情况下,就需要将循环体编译为机器码,而不是将main方法编译为机器码,这个时候就需要在循环入口处判断是否该循环体已经被编译为机器码。

由于这种编译方式不需要等待方法的执行结束,因此也被称为栈上替换编译,或简称OSR(OnStackReplacement)编译。一个方法究竟要被调用多少次,或者一个循环体究竟需要执行多少次循环才可以达到这个标准?必然需要一个明确的阈值,JIT编译器才会将这些“热点代码”编译为机器码执行。这里主要依靠热点探测功能。比如上面代码的循环次数为20000次,那么就可能在循环执行5000次的时候开始被编译,然后在第5200次循环的时候开始使用机器码,中间的20次循环依然是解释执行,因为编译也是需要消耗时间的。


目前 HotSpot VM 所采用的热点探测方式是基于计数器的热点探测。HotSpot VM 会为每个方法都建立两个不同类型的计数器,分别为方法调用计数器(ImvocationCounter)和回边计数器(Back Edge Counter)。

方法调用计数器用于(统计方法的调用次数,回边计数器则用于统讦循环体执行的循环次数。

方法调用计数器

JVM方法调用计数器的默认阈值在 Client 模式下是 1500 次,在 Server 模式下是 10000 次。超过”个阈值,就会触发JT编译。这个值可以通过虚拟机参数-XX:CompileThreshold 来手动设定一般而言,如果以缺省参数启动Java程序,方法调用计数器统计的是一段时间之内被调用的次数。当超过一定的时间限度,如果方法的调用次数没有达到方法调用计数器的值,这个方法的调用计数器的数值调整为当前数值的1/2,比如10分钟之内方法调用计数器数值为1000,下次执行该方法的时候,方法调用计数器的数值从500开始计数。这个过程称为方法调用计数器热度的衰减(CounterDecay),而这段时间就称为此方法统计的半衰周期(Counter Half Life Time),可以使用 -XX:CounterHalfLifeTime 参数设置半衰周期的时间

可以使用JVM参数“-XX:-UseCounterDecay”关闭热度衰减,让方法计数器统计方法调用的绝对次数,这样,只要系统运行时间足够长,绝大部分方法 (调用次数的统计没有时间限制) 都会被编译成机器码。一般而言,如果项目规模不大,并且产品上线后很长一段时间不需要进行版本迭代,都可以尝试把热度衰减关闭,这样可以使Java程序在线上运行的时间越久,执行性能会更佳

如图11-11所示,当一个方法被调用时,会先检查该方法是否存在被JIT编译过的版本,如果存在,则编译执行。如果不存在已被编译过的版本,则将此方法的调用计数器值加1,然后判断方法计数器的数值是否超过设置的阈值。如果已超过值,那么将会向ЛT申请代码编译,如果没有超过阈值,则继续解释执行。


回边计数器


回边计数器的作用是统计一个方法循环体代码执行的次数在字节码中遇到控制流向后跳转的指令称为“回边”(Back Edge),回边可简单理解为循环末尾跳转到循环开始。回边计数器的流程如下所示,当程序执行过程中遇到回边指令时,判断是否已经存在编译的机器码,如果存在,则编译执行即可,如果不存在,则回边计数器加1,再次判断是否超过值,如果没有超过,则解释执行,如果超过阈值,则向编译器提交编译请求,之后编译器开始编译代码,程序继续解释执行。回边计数器的值可以通过参数“-XX:OnStackReplacePercentage设置。显然,建立回边计数器统计的目的就是为了触发OSR 编译如图 11-12所示

3.两种JIT编译器

下面我们可以看看JIT的两种编译器:

C1、C2编译器,请移步:《剑指JVM》——第11章——JIT的两种编译器C1、C2——执行引擎6-CSDN博客



💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖

热门专栏推荐

🌈🌈计算机科学入门系列                     关注走一波💕💕

🌈🌈CSAPP深入理解计算机原理        关注走一波💕💕

🌈🌈微服务项目之黑马头条                 关注走一波💕💕

🌈🌈redis深度项目之黑马点评            关注走一波💕💕

🌈🌈JAVA面试八股文系列专栏           关注走一波💕💕

🌈🌈JAVA基础试题集精讲                  关注走一波💕💕   

🌈🌈代码随想录精讲200题                  关注走一波💕💕


总栏

🌈🌈JAVA基础要夯牢                         关注走一波💕💕  

🌈🌈​​​​​​JAVA后端技术栈                          关注走一波💕💕  

🌈🌈JAVA面试八股文​​​​​​                          关注走一波💕💕  

🌈🌈JAVA项目(含源码深度剖析)    关注走一波💕💕  

🌈🌈计算机四件套                               关注走一波💕💕  

🌈🌈数据结构与算法                           ​关注走一波💕💕  

🌈🌈必知必会工具集                           关注走一波💕💕

🌈🌈书籍网课笔记汇总                       关注走一波💕💕         



📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!

  • 30
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值