如何理解JVM中的JIT即时编译及优化技术

发布时间:2021-10-23 16:17:28 作者:柒染
来源:亿速云 阅读:152

这篇文章给大家介绍如何理解JVM中的JIT即时编译及优化技术,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

JVM Client 模式和 Server模式的区别

如何理解JVM中的JIT即时编译及优化技术

通过 java -version 可查看 JVM 所处的模式,并可以通过修改配置文件进行配置,那它们有什么区别呢?

Server:-Server 模式启动时,速度较慢,但是启动之后,性能更高,适合运行服务器后台程序

Client:-Client 模式启动时,速度较快,启动之后不如 Server,适合用于桌面等有界面的程序

热点代码

理解

当虚拟机发现某个方法或代码块的运行特别频繁时,就会把这些代码认定为“热点代码”。

热点代码的分类

上面提到的多次是一个不具体的词语,那到底是多少次才能成为热点代码呢?

如何检测热点代码

判断一段代码是否是热点代码,是否需要触发即使编译,这样的行为称为热点探测,热点探测并不一定知道方法具体被调用了多少次,目前主要的热点探测判定方式有两种:

HotSpot使用第二种 - 基于计数器的热点探测方法。

确定了检测热点代码的方式,如何计算具体的次数呢?

计数器的种类(两种共同协作)

了解了热点代码和计数器有什么用呢?达到计数器的阈值会触发后文讲解的即时编译,也就是说即时编译是需要达到某种条件才会触发的,先写结论,后文讲解什么是即时编译器。

两个计数器的协作(这里讨论的是方法调用计数器的情况):当一个方法被调用时,会先检查该方法是否存在被 JIT(后文讲解) 编译过的版本,如果存在,则优先使用编译后的本地代码来执行。如果不存在已被编译过的版本,则将此方法的调用计数器加 1,然后判断方法调用计数器与回边计数器之和是否超过方法调用计数器的阈值。如果已经超过阈值,那么将会向即时编译器提交一个该方法的代码编译请求。

当编译工作完成之后,这个方法的调用入口地址就会被系统自动改成新的,下一次调用该方法时就会使用已编译的版本。

字节码、机器码、本地代码?

字节码是指平常所了解的 .class 文件,Java 代码通过 javac 命令编译成字节码

机器码和本地代码都是指机器可以直接识别运行的代码,也就是机器指令

字节码是不能直接运行的,需要经过 JVM 解释或编译成机器码才能运行

此时你要问了,为什么 Java 不直接编译成机器码,这样不是更快吗?

1. 机器码是与平台相关的,也就是操作系统相关,不同操作系统能识别的机器码不同,如果编译成机器码那岂不是和 C、C++差不多了,不能跨平台,Java 就没有那响亮的口号 “一次编译,到处运行”;

2.之所以不一次性全部编译,是因为有一些代码只运行一次,没必要编译,直接解释运行就可以。而那些“热点”代码,反复解释执行肯定很慢,JVM在运行程序的过程中不断优化,用JIT编译器编译那些热点代码,让他们不用每次都逐句解释执行;

3.还有一方面的原因是后文讲解的解释器与编译器共存的原因。

什么是 JIT ?

为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器(Just In Time Compiler),简称 JIT 编译器

什么是编译和解释?

编译器:把源程序的每一条语句都编译成机器语言,并保存成二进制文件,这样运行时计算机可以直接以机器语言来运行此程序,速度很快;

解释器:只在执行程序时,才一条一条的解释成机器语言给计算机来执行,所以运行速度是不如编译后的程序运行的快的;

通过javac命令将 Java 程序的源代码编译成 Java 字节码,即我们常说的 class 文件。这是我们通常意义上理解的编译。

字节码并不是机器语言,要想让机器能够执行,还需要把字节码翻译成机器指令。这个过程是Java 虚拟机做的,这个过程也叫编译。是更深层次的编译。(实际上就是解释,引入 JIT 之后也存在编译)

此时又有疑惑了,Java不是解释执行的吗?

没错,Java 需要将字节码逐条翻译成对应的机器指令并且执行,这就是传统的 JVM 的解释器的功能,正是由于解释器逐条翻译并执行这个过程的效率低,引入了 JIT 即时编译技术。

必须指出的是,不管是解释执行,还是编译执行,最终执行的代码单元都是可直接在真实机器上运行的机器码,或称为本地代码

附一张图来理解

如何理解JVM中的JIT即时编译及优化技术

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

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

解释器:当程序需要迅速启动和执行的时候,解释器可以首先发挥作用,省去编译的时间,立即执行。

编译器:在程序运行后,随着时间的推移,编译器逐渐发挥作用,把越来越多的代码编译成本地代码之后,可以获取更高的执行效率。

两者的协作:在程序运行环境中内存资源限制较大时,可以使用解释执行节约内存,反之可以使用编译执行来提升效率。当通过编译器优化时,发现并没有起到优化作用,,可以通过逆优化退回到解释状态继续执行。

即时编译器与 Java 虚拟机的关系

即时编译器并不是虚拟机必需的部分,Java 虚拟机规范并没有规定 Java 虚拟机内必须要有即时编译器的存在,更没有限定或指导即时编译器应该如何去实现。

但是,即时编译器编译性能的好坏、代码优化程度的高低却是衡量一款商用虚拟机优秀与否的最关键的指标之一。它也是虚拟机中最核心且最能体现虚拟机技术水平的部分。

即时编译器的分类

目前主流的 HotSpot 虚拟机(JDK1.7 及之前版本的虚拟机)默认采用一个解释器和其中一个编译器直接配合的方式工作,程序使用哪个编译器,取决于虚拟机运行的模式,就是文章开头提到的两种模式。

在 HotSpot 中,解释器和 JIT 即时编译器是同时存在的,他们是 JVM 的两个组件。对于不同类型的应用程序,用户可以根据自身的特点和需求,灵活选择是基于解释器运行还是基于 JIT 编译器运行。HotSpot 为用户提供了几种运行模式供选择,可通过参数设定,分别为:解释模式、编译模式、混合模式,HotSpot 默认是混合模式,需要注意的是编译模式并不是完全通过 JIT 进行编译,只是优先采用编译方式执行程序,但是解释器仍然要在编译无法进行的情况下介入执行过程。

分层编译

产生的原因:由于即时编译器编译本地代码需要占用程序运行时间,要编译出优化程度更高的代码,所花费的时间可能更长;而且要想编译出优化程度更高的代码,解释器可能还要替编译器收集性能监控信息,这对解释执行的速度也有影响。为了在程序启动响应速度与运行效率之间达到最佳平衡,HotSpot 虚拟机启用分层编译的策略

分层编译根据编译器编译、优化的规模与耗时,划分出不同的编译层次:

实施分层编译后,Client Compiler 和 Server Compiler 将会同时工作,许多代码都可能会被多次编译看,用 Client Compiler 获取更高的编译速度,用 Server Compiler 获取更好的编译质量,在解释执行的时候也无须再承担收集性能监控信息的任务。

编译优化技术

Java 程序员有一个共识,以编译方式执行本地代码比解释执行方式更快,之所以有这样的共识,除去虚拟机解释执行字节码时额外消耗时间的原因外,还有一个重要的原因就是虚拟机设计团队几乎把对代码的所有优化措施都集中在了即时编译器中,因此一般来说,即时编译器产生的本地代码会比 javac 产生的字节码更优秀。以下是具有代表性的 HotSpot 虚拟机的即时编译器在生成代码时采用的代码优化技术:

如果能证明一个对象不会逃逸到方法或线程之外,也就是别的方法或线程无法通过任何途径访问到这个对象,则可以为这个变量进行一些高效的优化:

关于如何理解JVM中的JIT即时编译及优化技术就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

推荐阅读:
  1. PostgreSQL11 编译支持JIT功能
  2. Java虚拟机即时编译器技术JIT

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

jvm

上一篇:怎么理解三值逻辑与NULL

下一篇:jvm常用参数配置有哪些呢

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》