您的位置 首页 java

Java是解释执行还是编译执行的?

1、解释执行和编译执行的区别

Java代码要想放到JVM里去运行,首先需要经过Javac的编译,将Java代码编译为字节码Class文件。
Class文件反汇编后就是一条条JVM指令了,但是这些指令JVM认识,计算机可不认识。

JVM想要执行这些指令,该怎么办呢?

1.1、解释执行

将JVM指令逐行翻译为本地机器码,逐行解释,逐行执行。

优点:程序启动速度很快。
缺点:程序执行速度很慢。

1.2、编译执行

将Class文件直接编译成本地机器码并缓存下来,CPU可以直接执行。

优点:执行时省去了解释的过程,执行速度很快。
缺点:编译过程比较耗时,程序启动速度很慢。


2、Java是解释执行还是编译执行?

这个问题并没有统一的答案,JVM规范并没有强制要求JVM实现应该使用哪种方式来执行程序,只能说不同的JVM实现的方式不一样。
有纯解释执行的、纯编译执行的(JRockit)、还有解释+编译两者混用的(HotSpot)。

2.1、解释器和编译器

目前主流的商用JVM(如HotSpot)内部都同时包含解释器+编译器。

解释器与编译器两者各有优势:

  1. 当程序需要迅速启动时,解释器可以发挥优势,省去编译的时间,立即执行。
  2. 程序启动后,随着时间的推移,编译器开始发挥作用,JVM会将越来越多的热点代码编译成本地代码,减少解释器的中间损耗,获得更高的执行效率。

使用参数-Xint可以要求JVM只使用解释器,这时编译器完全不介入工作,所有代码均通过解释执行。
参数-Xcomp要求JVM优先编译执行,但是解释器仍然要在编译器无法进行的情况下介入工作。

2.2、何时编译?

能触发JIT编译的热点代码有两类:

  1. 多次调用的方法
  2. 多次调用的循环体

不管是方法被多次调用,还是某一段循环体代码被多次调用,JIT编译的最小单位都是整个方法体。
如果一个方法被JIT编译后,下次JVM再执行这个方法时,就会直接编译执行。
而对于一个循环体而言,由于方法已经打包成栈帧入栈执行了,JVM必须在方法运行时进行替换,因此也被称为“栈上替换”。

2.2.1、热点探测

方法被多次执行,这个【多次】指的到底是多少次呢?JVM如何判断代码是否属于热点代码呢?这就需要热点探测技术的支持了。

目前主流的热点探测技术有两种:

  • 基于采样的热点探测

JVM周期性的检查线程方法栈顶,进行数据采样,如果发现某些方法经常出现在栈顶,就认为它是热点代码。
这种方式实现简单高效,但是统计结果会有误差,因为方法经常出现在栈顶不一定是执行次数多,也可能是 方法阻塞 了。

  • 基于计数器的热点探测

JVM为每个方法(甚至是代码块)维护一个计数器,每调用一次计数器就加1,计数器超过阈值后就会被认为是热点代码。
这种方式实现复杂,需要为每个方法都维护一个计数器,但是统计结果准确。

HotSpot采用的就是基于计数器的热点探测。

2.2.2、方法调用计数器和回边计数器

HotSpot为每个方法准备了两个计数器:方法调用计数器、回边计数器。

  • 方法调用计数器

统计方法被调用的次数,Client模式下阈值为1500次,Server模式下阈值为10000次,阈值可以通过JVM参数-XX:CompileThreshold设置,默认情况下,方法调用次数统计的并不是绝对次数,而是一段时间内的调用频率,在一个时间段内如果调用次数不足以触发编译,次数就会减半进入半衰期,可以使用参数-XX:-UseCounterDecay来关闭热度衰减,关闭后统计的就是绝对次数了,时间长了几乎所有的代码都会被编译执行。

  • 回边计数器

统计方法中循环体代码的执行次数,在字节码中遇到控制流程向后跳转的指令就称为“回边”,例如For、While循环。遇到一次回边指令,回边计数器就会加1,当计数器超过阈值后就会触发热点代码编译,回边计数器没有半衰期,统计的是绝对次数。

触发热点代码编译后,程序会继续解释执行,只有当编译工作完成以后,系统会将方法的调用入口地址写入新值,下一次再调用该方法,才会使用已编译的版本。


3、性能实战比较

如下代码,调用一亿次偶数判断,分别使用-Xint、-Xcomp来解释执行、编译执行,查看两者执行效率。

Java是解释执行还是编译执行的?

执行结果:

执行类型

耗时(ms)

-Xint

6334

-Xcomp

254

可以看到,两者的执行效率差距还是很明显的。


4、尾巴

不管是编译执行还是解释执行,对用户来说都是透明的,也都不会影响程序的运行结果,但是两者的性能差距却非常明显。
在开发模式下,希望服务尽快启动完成,不在乎执行效率,可以使用解释执行来快速启动。
而对于线上服务,启动时间可以慢一点,但是非常在意程序的执行效率,则可以考虑使用编译执行。

文章来源:智云一二三科技

文章标题:Java是解释执行还是编译执行的?

文章地址:https://www.zhihuclub.com/182869.shtml

关于作者: 智云科技

热门文章

网站地图