JVM源码剖析之达到什么条件进行JIT优化

news/2024/11/28 4:47:47/

版本信息: 

jdk版本:jdk8u40

思想至上

技术经过数百年的迭代,如今虚拟机中都存在JIT模块,JVM中Hotspot,Android虚拟机中dalvik、Art等等。并且存在一个共性,全部都是解释器和JIT共存。当然,如今都存在AOT编译(Ahead of Time Compiler)将Java文件直接编译成平台相关可执行文件,这并不是本文改论述的点。

在Hotspot虚拟机中执行引擎包括解释器、JIT及时编译器。从" Hotspot " 这个单词也能看出,此虚拟机为了热点而生。Hotspot虚拟机默认允许2大执行引擎同时进行工作,在正常情况下使用解释器进行工作,当达到一定阈值后从解释器转为JIT编译器工作(PS:当然,一切都可由开发者高度配置,比如:只允许解释器,比如转换阈值变低等等,为了篇幅,这里并不会把配置参数提供出来)

因为JIT编译器是在运行时编译,所以需要一定的编译时间,而解释器启动就可用,所以Hotspot中同时存在解释器和JIT、从解释器过度到JIT。并且在JIT中还分为c1编译器、c2编译器。为何同时存在c1、和c2编译器呢,原因也很简单,因为c1编译耗时少,但是编译出来的代码执行效率一般。而c2编译器编译耗时长,但是编译出来的代码执行效率高,并且会存在过激的编译。所以在Hotspot中同时存在c1和c2编译器,用于从c1过度到c2。所以在Hotspot中从解释器到编译器,一层一层的过度,其实是在编译时间和执行效率中做折中。

源码论证

从上文可以得知,在Hotspot 中默认是从解释器优化成JIT,所以在解释器执行过程中肯定存在一些值用于记录执行数据,并且达到一定的阈值就会开始进行JIT优化。而我们在思考,在Java代码中可以执行的代码都存在方法中,包括<init>和<clinit>,所以用于记录执行数据的变量是不是在方法中呢?

/src/share/vm/oops/method.hpp 文件中

class Method : public Metadata {
friend class VMStructs;…………// 用于记录方法的执行相关的次数,目的很简单,为了jit优化。MethodCounters*   _method_counters;…………
}

/src/share/vm/oops/methodCounters.hpp 文件中

class MethodCounters: public MetaspaceObj {friend class VMStructs;private:…………// 记录方法执行次数InvocationCounter _invocation_counter;         // 记录方法中的跳转次数(if,while,for,switch等等)InvocationCounter _backedge_counter;     …………      
}

从上述代码中可以得到在方法中存在MethodCounters类用于记录运行时的数据。而在MethodCounters类中定义了2个计数器。分别是方法执行计数器、回边计数器(记录方法中存在跳转相关的指令,比如if,while,for,switch)。而计数器达到JIT优化的阈值就会开启优化(如果是开启分层编译的话,此阈值会发生动态的变化,并不是固定的,此时将根据当前待编译的方法数以及编译线程数来动态调整)

方法执行计数器

在x86平台下,c1的阈值为1500,c2的阈值是10000。不过在分层编译开启的情况下此阈值会失效,从而变成动态阈值。

// /src/cpu/x86/vm/c1_globals_x86.hpp define_pd_global(intx, CompileThreshold, 1500 );
// /src/cpu/x86/vm/c2_globals_x86.hpp define_pd_global(intx, CompileThreshold, 10000);

回边计数器

在x86平台下,c1的阈值为100000,c2的阈值是100000。不过在分层编译开启的情况下此阈值会失效,从而变成动态阈值。

// /src/cpu/x86/vm/c1_globals_x86.hpp define_pd_global(intx, BackEdgeThreshold,            100000);
// /src/cpu/x86/vm/c2_globals_x86.hpp define_pd_global(intx, BackEdgeThreshold,            100000);

http://www.ppmy.cn/news/978090.html

相关文章

安卓版本的发展4-13

Android 4.4 KitKat 1、通过主机卡模拟实现新的 NFC 功能。 2、低功耗传感器&#xff0c;传感器批处理&#xff0c;步测器和计步器。 3、全屏沉浸模式&#xff0c;隐藏所有系统 UI&#xff0c;例如状态栏和导航栏。它适用于鲜艳的视觉内容&#xff0c;例如照片、视频、地图、…

获取客户端真实 IP 地址的最佳实践

一、背景 1. 业务上云带来性能收益 公司从去年全面推动业务上云&#xff0c;而以往 IDC 架构部署上&#xff0c;接入层采用典型的 4 层 LVS 多机房容灾架构&#xff0c;在业务高峰时期&#xff0c;扩容困难&#xff08;受限于物理机资源和 LVS 内网网段的网络规划&#xff09…

如何使用Flask-Bootstrap和Flask-Moment来简化Flask应用程序的开发?

Flask-Bootstrap和Flask-Moment是两个强大的扩展&#xff0c;可以帮助你轻松地集成Bootstrap和Moment.js到你的Flask应用程序中。 首先&#xff0c;让我们来安装这两个扩展吧&#xff01;可以使用pip来安装它们&#xff1a; pip install flask-bootstrap flask-moment安装完成…

ElasticSearch Java API 操作

1.idea创建Maven项目 2.添加依赖 修改 pom.xml 文件 <dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.8.0</version></dependency><!-- elasticsearch 的客户端 --…

网络安全.域名备案和ICP备案

首先我们来了解一下域名备案和ICP备案分别代表什么意义。 域名备案一般需要1至3个工作日的时间进行审核&#xff0c;而ICP备案的审核时间较长&#xff0c;需要在5至20个工作日的时间内完成。域名备案方面主要考虑域名的合法性和域名归属人信息的真实性&#xff0c;而ICP备案方…

C++ STL sort函数的底层实现

C STL sort函数的底层实现 sort函数的底层用到的是内省式排序以及插入排序&#xff0c;内省排序首先从快速排序开始&#xff0c;当递归深度超过一定深度&#xff08;深度为排序元素数量的对数值&#xff09;后转为堆排序。 先来回顾一下以上提到的3中排序方法&#xff1a; 快…

kafka权限控制功能

参考链接&#xff1a; https://www.clougence.com/cc-doc/dataMigrationAndSync/database/privs_for_kafka Kafka需要的权限 | CloudCanal of ClouGence Kafka Topic 权限控制可以通过使用 Apache Kafka 的内置安全特性来实现。这主要涉及到两个方面&#xff1a;认证&#…

Linux6.14 Docker Compose容器编排

文章目录 计算机系统5G云计算第四章 LINUX Docker Compose容器编排一、Compose概述1.Docker Compose 的概述2.Docker Compose 三大的概念 二、部署过程1.Docker Compose 环境安装2.YAML 文件格式及编写注意事项3.Docker Compose配置常用字段4.Docker Compose 常用命令5.Docker …