学习java必不可少的环节---JVM解析(1.3)

Java即时编译器的问题

  • 为何JVM需要使用解释器和编译器并存的架构?
  • JVM为什么要实现两个不同的编译器?
  • 程序何时会使用解释器执行?何时会使用编译器执行?
  • 哪些程序代码会被编译成为本地代码?如何编译?
  • Java代码的执行效率就一定比C,C++静态执行的执行差?Java代码解析执行有和何优势?

1.为什么HotSpot虚拟机要使用解释器与编译器并存的架构?

    尽管并不是所有的Java虚拟机都采用 解释器与编译器并存的架构,但许多主流的商用虚拟机(eg:HotSpot),
都同时包含解释器和编译器?

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

  • 当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行,在程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码后,可以获取更高的执行效率。
  • 当程序运行环境中内存资源限制较大(如部分嵌入式系统中),可以使用解释器执行节约内存,反之可以使用编译器执行来提升效率

编译的时间开销

解释器的执行,抽象的看是这样的:
输入的代码–>[解释器 解释执行]–>执行结果
需要JIT编译后再执行的话,抽象的看则是:
输入的代码–>[编译器 编译]–>编译后的代码–>[执行]–>执行结果

说JIT比解释快,其实说的是“执行编译后的代码”比“解释器解释执行”要快,并不是说“编译”这个动作比“解释”这个动作快,JIT编译再怎么快,至少也比解释执行一次略慢一些,而要得到最后的执行结果还得经过一个“执行编译后的代码”的过程。所以,对“只执行一次”的代码而言,解释执行其实总是比JIT编译执行要快

怎么算是“只执行一次的代码”呢?粗略说,下面两个条件同时满足就是严格的“只执行一次”

  • 只被调用一次,例如类的构造器
  • 没有循环
    对只执行一次的代码做JIT编译再执行,可以说是得不偿失
    岁只执行少量次数的代码,JIT编译带来的执行速度的提升也未必能抵消最初编译带来的开销。

只有对频繁执行的代码,JIT编译才能保证有正面的收益

编译空间的开销

对一般的Java方法而言,编译后代码的大小相对于字节码的大小,膨胀比达到10x是很正常的。同上面说的时间开销一样,这里的空间开销也是,只有对执行频繁的代码才值得编译,如果把所有代码都编译则会显著增加代码所占空间,导致“代码爆炸”。

这也就解释了为什么有些JVM会选择不总是做JIT编译,而是选择用解释器+JIT编译器的混合执行引擎

2.为何HotSpot虚拟机要实现两个不同的即时编译器?

HotSpot虚拟机中内置了两个即时编译器:Client Complier和Server Complier,分别用在客户端和服务器端

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

用Client Complier获取更高的编译速度,用Server Complier来获取更好的编译质量。为什么提供多个即时编译器与为什么提供多个垃圾回收器类似,都是为了适用不同的应用场景

3.哪些程序代码会被编译?

程序中的diam只有是热点代码时,才会编译为本地代码,那么什么是“热点代码”呢?
运行过程中会被即时编译器编译的“热点代码”有两类:

  • 被多次调用的方法
  • 被多次执行的循环体
    两种情况,编译器都是以整个方法作为编译对象。这种编译方法因为编译发生在方法执行过程之中,因此形象的称之为栈上替换,即方法栈帧还在栈上,方法就被替换

4.如何判断热点代码?

要知道方法或一段代码是不是热点代码,是不是需要触发即时编译,需要进行Hot Spot Detection(热点探测)
目前主要的热点探测方法有以下两种:

  • 基于采样的热点探测

采用这个方法的虚拟机会周期性地检查各个线程的栈顶,如果发现某些方法经常出现在栈顶,那这个方法就是“热点方法”。这种探测方法的好处是实现简单高效,还可以很容易地获取方法调用关系(将调用堆栈展开即可),缺点是很难精确地确认一个方法的热度,容易因为受到线程阻塞或别的外界因素的影响而扰乱热点探测

  • 基于计数点的热点探测

采用这种方法的虚拟机会为每个方法(甚至是代码块)建立计数器,统计方法的执行次数,如果执行次数超过一定的阈值,就认为它是热点方法。这种统计方法实现复杂一些,需要为每个方法建立并维护计数器,而且不能直接获取到方法的调用关系,但是它的统计结果相对更加精确严谨。

5.HotSpot虚拟机中使用的是何种热点检测方式?

    在HotSpot虚拟机中使用的是第二种--基于计数器的热点探测方法,因此它为每个方法准备了两个计数器:
方法调用计数器和回边计数器。在确定虚拟机运行参数的前提下,这两个计数器都有一个确定的阈值,当计数器
超过阈值溢出了,就会触发JIT编译

方法调用计数器
顾名思义,这个计数器用于统计方法被调用的次数
在这里插入图片描述

回边计数器
它的作用就是统计一个方法中循环体代码执行的次数,在字节码中遇到控制流向后跳转的指令称为“回边”

6.如何编译为本地代码?

Server Complier和Client Complier两个编译器的编译过程是不一样的

对Client Complier来说,它是一个简单快速的编译器,主要关注点在于局部优化,而放弃许多耗时较长的全局优化手段

而Server Complier则是专门面向服务端的,并为服务端的性能配置特别调整过的编译器,是一个充分优化过的高级编译器

猜你喜欢

转载自blog.csdn.net/qq_44787898/article/details/109097377