分层编译这两种编译方式是怎么协作的呢?
HotSpot虚拟机包含多个即时编译器C1、C2和Graal 。其中,Graal是一个实验性质的即时编译器,可以通过参数 -XX:+
UnlockExperimentalVMOptions -XX:+UseJVMCICompiler启用,并且替换C2 。
C1和C2各有优劣,适用于不同的场景 。在Java 7以前,只能选择一种编译器 。C1编译快,但生成的代码执行效率一般,常用于对于执行时间较短的,或者对启动性能有要求的程序,常用于客户端;C2编译慢,但生成的代码执行效率快,适用于对于执行时间较长的,或者对峰值性能有要求的程序,常用于服务端 。实际上,C1对应的参数是client,C2对应的参数是server,也跟它们的应用场景比较匹配 。
Java7引入了分层编译的概念,综合了C1的启动性能优势和C2的峰值性能优势 。C1和C2编译出的机器码是不同的 。C2代码的执行效率要比C1代码高出30%以上 。机器码越快,需要的编译时间就越长 。分层编译是一种折衷的方式,既能够满足部分不那么热的代码能够在短时间内编译完成,也能满足很热的代码能够拥有最好的优化 。
热点代码那怎么判定热点代码呢?
JVM会收集方法的运行时信息,主要包括调用次数和循环回边的次数 。当方法的调用次数和循环回边的次数的和,超过指定阈值时,便会触发即时编译 。
循环回边次数可以简单理解为方法内部代码的循环次数,比如方法内部有for循环或while循环 。在分层编译出现前,这个阈值是由参数
-XX:CompileThreshold
指定的,使用C1时,该值为1500;使用C2时,该值为10000 。当启用分层编译时,JVM使用另一套阈值系统 。在这套系统中,阈值的大小是动态调整的 。JVM将阈值与某个系数 s 相乘 。该系数与当前待编译的方法数目成正相关,与编译线程的数目成负相关 。
编译线程默认情况下编译线程的总数目是根据处理器数量来调整的 。Java 虚拟机会将这些编译线程按照1:2的比例分配给 C1和C2(至少各为1个) 。举个例子,对于一个四核机器来说,总的编译线程数目为3,其中包含一个C1编译线程和两个C2编译线程 。
机器资源太少的时候,也可能各1个线程 。用arthas可以看到编译线程:
可以看到,它们的ID是-1,优先级也是-1 。我们自己创建的线程优先级是0~10,所以编译线程的优先级会更高一些 。
总结一句话来总结Java程序是怎么在机器上运行的呢?首先Java程序员编写Java代码,然后Java代码会被编译成class文件,多个class文件会被打包成jar包或者war包 。然后JVM加载class文件,然后先解释执行为字节码 。程序运行一段时间后,JVM会通过方法调用次数和循环持续判断一个方法是否为热点代码,如果是,会使用分层编译,通过编译线程编译成字节码,在机器上运行 。
以上关于本文的内容,仅作参考!温馨提示:如遇健康、疾病相关的问题,请您及时就医或请专业人士给予相关指导!
「四川龙网」www.sichuanlong.com小编还为您精选了以下内容,希望对您有所帮助:- javascript选择器推荐 javascript选择器有哪些
- java字符串指定编码 java设置字符串编码
- java遍历list删除元素讲解 java遍历list删除元素
- java的三种注释类型 java脚本注释格式
- java线程暂停和恢复 线程暂停和恢复
- iis运行php慢解决方法 iis运行php久了非常慢
- java开发常用的框架 java框架都有哪些
- 附讲解和思维导图 java代码大全及详解
- java类和对象的基本概念 java中的对象是什么
- java程序入门及开发环境 java官方网站是多少