前言

本文记录日常学习《深入理解Java虚拟机》,不知道为啥感觉看一遍也就过了,喜欢动动手理解理解,这样才有点感觉,静不下心来的时候,看书抄书也可以用这个办法。

一、什么是JIT(Just In Time Compiler)即时编译器

在虚拟机中(Sun HotSpot),Java程序最初是通过解释器执行的,当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“热点代码”(Hot Spot Code)。为了提高热点代码的执行效率,在运行时,虚拟机会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器(Just In Time Compiler)。

Java虚拟机规范并没有规定java虚拟机内必须要有即时编译器存在,更没有限定和指导即时编译器应该如何去实现。但是即时编译器的好坏、代码优化程度的高低却是衡量一款商用虚拟机优秀与否的最关键指标之一,它也是虚拟机中最核心最能体现虚拟机水平的部分。

二、JVM内置的两个即时编译器

C1编译器:Client Compiler
C2编译器:Server Compiler

HotSpot虚拟机,默认采用解释器与其中一个编译器直接配合的方式工作,程序使用哪个编译器,取决于虚拟机运行的模式,HotSPot虚拟机会根据自身版本与宿主机器的硬件性能自动选择运行模式。也可以使用“-client”和“-server”参数去强制指定虚拟机运行在Client模式还是Server模式。

[root@ip-10-0-0-90 ~]# java -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, mixed mode) [root@ip-10-0-0-90 ~]# java -Xint -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, interpreted mode) [root@ip-10-0-0-90 ~]# java -Xcomp -version
java version "1.8.0_151"
Java(TM) SE Runtime Environment (build 1.8.0_151-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.151-b12, compiled mode)

三、JVM的分层策略

第0层:程序解释执行,解释器不开启性能监控功能(Profiling),可触发第一层编译。
第1层:也称C1编译,将字节码编译为本地代码,进行简单、可靠的优化,如有必要将加入性能监控的逻辑。
第2层(或2层以上):也称C2编译,将字节码编译为本地代码,但是会启用一些编译耗时较长的优化,甚至会根据性能监控信息进行一些不可靠的激进优化。

分层策略在JDK8是默认开启的,C1编译可获取更高的编译速度,C2编译可获取更好的编译质量。

四、编译对象和触发条件

编译对象:

1)被多次调用的方法
2)被多次执行的循环体

触发条件:

1)基于采样的热点探测
采用这种方法的虚拟机会周期性的检查各个线程的栈顶,如果发现某个或某些方法经常出现在栈顶,那这个方法就是“热点方法”。

2)基于计数器的热点探测
采用这种方法的虚拟机会为每个方法(或代码块)建立计数器,统计方法的执行次数,如果执行次数超过一定的值就认为他是“热点方法”。

五、JIT编译方式和OSR编译方式

JIT编译方式

方法调用触发的编译,编译器会以整个方法作为编译对象,这种编译也是虚拟机中标准的JIT编译方式。

OSR编译方式

循环体调用触发的编译即使是由循环体触发的,但编译器会以整个方法(而不是单独的循环体)作为编译对象。这种编译方式因为编译发生在方法执行过程中,因此形象的称为栈上替换(On Stack Replacement)简称OSR编译,即方法栈帧还在栈上,方法就被替换了。

六、方法计数器和回边计数器

在HotSpot虚拟机中,使用的是基于计数器的热点探测,他为每个方法准备了两类计数器,方法调用计数器(Incocation Counter) 和回边计数器(Back Edge Counter)。这两个计数器都有一个阀值,当计数器超过了这个阀值,就会触发JIT编译。

1)方法调用计数器

用于统计方法被调用的次数,默认阀值为Client模式下:1500次,Server模式下10000次;这个阀值可以通过虚拟机参数-XX:CompileThreshold设定。当一个方法被调用时,会先检查该方法是否存在被JIT编译过的版本,如果存在,则优先使用编译后的本地代码来执行。如果不存在已被编译过的版本,则将此方法的调用计数器值加1,然后判断方法调用启与回边计数器值之和是否超过方法调用计数器的阀值,如果超过阀值,那么将会向即时编译器提交该方法的代码编译请求。

在默认情况下,执行引擎不会同步等待编译请求完成,而是继续进入解释器按照解释方式执行字节码,直到提交的请求被编译器编译完成。当编译工作完成后,这个方法的调用入口地址就会被系统自动改写成新的,下一次调用该方法时就会使用已编译的版本。

注:
如果不做任何设置,方法调用计数器统计的并不是方法被调用的绝对次数,而是相对执行频率,即在一段时间之内方法被调用的次数。当超过一定的时间限度,如果方法的调用次数仍然不足以让他提交给即时编译器,那这个方法的调用计数器就会被减少一半,这个过程称为方法调用计数器热度的衰减(Counter Decay),而这段时间就称为此方法统计的半衰周期(Counter Half Life Time)。进行热度衰减的动作是在虚拟机进行垃圾收集时顺便进行的,可以使用虚拟机参数-XX:-UseCounterDecay来关闭热度衰减,让方法计数器统计方法调用的绝对次数,这样只要系统运行时间足够长,绝大部分方法都会被编译成本地代码。另外,可以使用-XX:CounterHalflifeTime参数设置半衰周期的时间,单位为s。

2)回边计数器

回边计数器,他的作用是统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为“回边”(back Edge),建立回边计数器统计的目的就是为了触发OSR编译。

想买保时捷的运维李先生学Java性能之 JIT即时编译器的更多相关文章

  1. 想买保时捷的运维李先生学Java性能之 运行时数据区域

    前言 不知道自己不知道,不知道自己知道,知道自己不知道,知道自己知道,目前处于知道自己不知道这个阶段,很痛苦啊,干了4年了运维,是一个坎.越来越发觉想要走得远,还是得扎根底.   一.运行时数据区域 ...

  2. 想买保时捷的运维李先生学Java性能之 生存与毁灭

    一.判断对象是否存活     1.引用计数算法   给对象中添加一个引用计数器,每当有一个地方引用它时,计数器就加1:当引用失效时,计数器的值就减1:任何时刻计数器为0的对象是不可能再被使用的.引用计 ...

  3. 想买保时捷的运维李先生学Java性能之 垃圾收集算法

    前言 从原来只知道-Xms.-Xmx是设置内存的,到现在稍微理解了一些堆内存等Java虚拟机的一些知识.明白了技术这一个东西还是得要有输入才能实践,原理与实践要相辅相成,后续把JVM的监控好好总结一下 ...

  4. 想买保时捷的运维李先生学Java性能之 垃圾收集器

    前言 垃圾收集算法是内存回收的方法论:垃圾收集器是内存回收的具体实现.Java虚拟机规范中对垃圾收集器应该如何实现并没有任何规定,因此不同的厂商.不同版本的虚拟机所提供的垃圾收集器都有很大的差别,并且 ...

  5. Linux运维不可不知的性能监控和调试工具

    Linux运维不可不知的性能监控和调试工具 1 nagios Nagios是一个开源监控解决方案,我觉得他可以监控一切 ,可以看一下我以前的文章:NAGIOS 2 ps #用来查看程序的运行情况 ps ...

  6. 从零起步做到Linux运维经理, 你必须管好的23个细节

    “不想成为将军的士兵,不是好士兵”-拿破仑 如何成为运维经理? 一般来说,运维经理大概有两种出身:一种是从底层最基础的维护做起,通过出色的维护工作,让公司领导对这个人非常认可,同时对Linux运维工作 ...

  7. 从零起步做到Linux运维经理,你必须管好的23个细节

    不想成为将军的士兵,不是好士兵-拿破仑 如何成为运维经理?成为运维经理需要什么样的能力?我想很多运维工程师都会有这样的思考和问题. 如何成为运维经理.一般来说,运维经理大概有两种出身,一种是从底层最基 ...

  8. 转:linux运维工程师

    运维中关键技术点解剖:1 大量高并发网站的设计方案:2 高可靠.高可伸缩性网络架构设计:3 网站安全问题,如何避免被黑?4 南北互联问题,动态CDN解决方案:5 海量数据存储架构 一.什么是大型网站运 ...

  9. 面试 Linux 运维工作至少需要知道哪些知识?

    前言 我们已经发过不少 Linux 面试题,但是单独的面试题总感觉会过于零碎,没有体系化内容给人的帮助大. 知乎上有这样一个问题:一个新手面试 Linux 运维工作至少需要知道哪些知识?其中有一个答案 ...

随机推荐

  1. git 修改已提交了的备注信息的方法

    git 修改已提交了的备注信息的方法: 1.当我们已通过 git commit -m '已提交的最新的备注' 命令将代码提交到了缓存区,或者进一步执行了 git push origin master ...

  2. (专题一)06 MATLAB的算术运算

    基本算术运算 乘法运算:A的行数等于B的列数(A,B两矩阵维数和大小相容) 除法运算 逻辑运算 真为1,假为0 优先级,算术运算的优先级最高,逻辑运算的优先级最低,但逻辑非运算是单目运算,他的优先级比 ...

  3. pytest封神之路第五步 参数化进阶

    用过unittest的朋友,肯定知道可以借助DDT实现参数化.用过JMeter的朋友,肯定知道JMeter自带了4种参数化方式(见参考资料).pytest同样支持参数化,而且很简单很实用. 语法 在& ...

  4. XXE漏洞介绍 & XXE漏洞攻击 & 修复建议

    介绍XXE漏洞 XML外部实体注入(XML External Entity)简称XXE漏洞,XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是-种允许用户对自己的标记语 ...

  5. GAN的理论 Theory behind GAN

    任务:想要找到一个高维空间中的分布 P_data(x),要在目标类别的区域,采样的概率是高的:在那个区域之外,probability是低的.但这个P_data(x)分布的具体形式(pdf)是不知道的, ...

  6. Mysql中 int(3) 类型的含义

    注意:这里的(3)代表的并不是存储在数据库中的具体的长度,以前总是会误以为int(3)只能存储3个长度的数字,int(11)就会存储11个长度的数字,这是大错特错的. 其实当我们在选择使用int的类型 ...

  7. 027 01 Android 零基础入门 01 Java基础语法 03 Java运算符 07 逻辑“与”运算符

    027 01 Android 零基础入门 01 Java基础语法 03 Java运算符 07 逻辑"与"运算符 本文知识点:Java中的逻辑"与"运算符 逻辑运 ...

  8. Python如何安装OpenCV库

    转载:https://blog.csdn.net/weixin_35684521/article/details/81953047 OpenCV的概念可百度,在此不再赘述.https://baike. ...

  9. GetDlgItem(函数详解)

    转载: https://blog.csdn.net/hk121/article/details/80942850 hwndScroll = GetDlgItem(hwnd, IDC_SCROLL); ...

  10. matlab中imfilter、conv2、imfilter2用法及区别

    来源 :https://blog.csdn.net/u013066730/article/details/56665308(比较详细) https://blog.csdn.net/yuanhuilin ...