Java内存学习-JIT(Just In Time) 即时编译器1

JIT编译器概念

前端编译器:JDK的Javac,即把*.java文件转变成*.class文件的过程
即时编译器:HotSpot虚拟机的C1,C2编译器,Graal编译器,JVM运行期把字节码转变成本地机器码的过程
提前编译器:JDK的Jaotc,GNU Compiler for the Java(GCJ)等

在这里插入图片描述在这里插入图片描述在这里插入图片描述

概念

字节码(bytecode)
本地机器码(native code)
垃圾回收stop-the-world (STW)
指令流水线(instruction pipeline)
解释器,解释执行模式( Interpreter )
即时编译器(Just In Time Compiler )
预先编译模式(ahead-of-time compilation mode)
混合模式(Mixed Mode)
解释模式(Interpreted Mode)
编译模式(Compiled Mode)
分层编译器(Tiered Compiler)
客户端编译器(Client Compiler)
服务端编译器(Server Compiler)
代码缓存池(Code Cache)
热点探测(Hot Spot Detection)
精准优化(Accurate Profiling)
启发法(heuristics)
基于采样的热点探测(Sample Based Hot Spot Detection)
基于计数器的热点探测(Counter Based Hot Spot Detection)
方法调用计数器(Invocation Counter )
回边( Back Edge )
回边计数器(Back Edge Counter )
方法调用计数器热度的衰减(Counter Decay)
方法的统计的半衰周期( Counter Half Life Time)
方法调用计数器阈值(CompileThreshold)
解释器监控比率 (InterpreterProfilePercent)
安全点(Safepoints)
高级中间代码表示(High-Level Intermediate Representaion , HIR)
低级中间代码表示(Low-Level Intermediate Representation ,LIR)
线性扫描算法(Linear Scan Register Allocation)
普通对象指针(ordinary object pointers, oops)
编译级别(Compilation Levels)
异常捕获块(exception handler)
阻塞模式(blocking mode)
本地方法标志(native method)
置为不可进入(made not entrant)
置为僵死模式(made zombie)

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

IBM JDK优化代码过程

阶段 1 - 内联

内联是将较小方法树并入,或“内联”到其调用者树的过程。 这可加快对经常执行的方法的调用速度。 根据当前优化级别,使用具有不同活跃级别的两种内联算法。 此阶段执行的优化包括:

细琐内联
调用图内联
尾部递归消除
虚拟调用监管优化
阶段 2 - 局部优化

布局优化一次分析并改进一小部分代码。 多个局部优化实现尝试并测试了在一流的静态编译器中使用的技术。 优化包括:

局部数据流分析和优化
寄存器使用优化
Java 成语的简单化

重复应用这些技术,尤其是在全局优化后,这可以指出更多改进的地方。

阶段 3 - 控制流优化

控制流优化分析方法内部的控制流(或者特定部分)并重新安排代码路径以提高效率。 优化包括:

代码重新排序、分割和移除
循环缩减和循环反演
循环步幅和循环不变量代码移动
循环展开和剥离
循环版本控制和专用化
异常定向优化
转换分析
阶段 4 - 全局优化

全局优化立即对整个方法生效。 它们的“成本更高”,需要更多的编译时间,但可显著提高性能。 优化包括:

全局数据流分析和优化
部分冗余消除
逃逸分析
GC 和内存分配优化
同步优化
阶段 5 - 本机代码生成

本机代码生成过程根据平台体系结构的不同而有所不同。 通常,在此编译阶段中,方法树将转换为机器码指令;并根据体系结构特征执行一些较小的优化。 已编译的代码将放入名为代码高速缓存的 JVM 过程空间的某一部分中;将记录代码高速缓存中方法的位置,以供今后针对调用已编译的代码而调用。 在任何指定的时间,JVM 过程由 JVM 可执行文件和一组 JIT 编译的代码组成,这些代码动态连接到 JVM 中的字节码解释器。

优化技术

栈上替换(On-stack replacement ,OSR)低优化层级向高优化层级的迁移
逆优化(Deoptimization)高优化层级向低优化层级的迁移叫做去优化uncommon trap

方法内联(Method Inlining)
逃逸分析(Escape Analysis)
无用代码消除(Dead Code Elimination)
循环展开(Loop Unrolling)
循环表达式外提(Loop Expression Hoisting)
消除公共子表达式(Common Subexpression Elimination)
局部公共子表达式消除(Local Common Subexpression Elimination)
全局公共子表达式消除(Global Common Subexpression Elimination)
常量传播(Constant Propagation)
基本块冲排序(Basic Block Reordering)
如范围检查消除(Range Check Elimination)
空值检查消除(Null Check Elimination )
守护内联(Guarded Inlining)
分支频率预测(Branch Frequency Prediction)

在这里插入图片描述
在这里插入图片描述

JVM参数

常用参数

-Xint:完全采用解释器模式执行程序。要完全禁用JIT编译器, 使用解释器来运行所有内容, 可以指定启动参数
-Xcomp:完全采用即时编译模式执行程序,如果即时编译出现问题,解释器会介入。
-Xmixed:采用解释器 + 即时编译的混合模式共同执行程序,是 JVM 默认的执行模式。

–XX:-TieredCompilation, 来禁用分级编译。
-XX:TieredStopAtLevel=1。如果要禁用C2, 只使用C1, 不增加分析的性能损耗, 可以传入启动参数
-XX:ReservedCodeCacheSize 调整 Code Cache 最大值
-XX:InitialCodeCacheSize 调整 Code Cache 初始值
-XX:+UseCodeCacheFlushing 控制Code Cache 清理机制,JIT关闭前尝试清理Codecache,如果清理后还是没有空间,那么JIT依然会关闭。这个选项默认是关闭的
-XX:+PrintCodeCache 可以查看CodeCache的使用情况(在启动时增加,在jvm关闭时会打印使用情况)
-XX:CICompilerCount 编译器线程数量
-XX:+BackgroundCompilation参数可以设置编译机器码的动作同步还是异步。默认是true(异步)。当设置为false时,执行该方法的代码将一直等到它确实被编译为机器码以后才会执行。用-Xbatch可以禁止后台编译。
-XX:+LogCompilation 记录编译器日志hotspot_pid.log
-XX:LogFile 指定日志文件目录
-XX:TierXBackEdgeThreshold:OSR编译的阈值
-XX:TierXMinInvocationThreshold:开启分层编译后各层调用的阈值
-XX:TierXCompileThreshold:开启分层编译后的编译阈值

编译阈值Compile Threshold

java -XX:+PrintFlagsFinal -version | grep CompileThreshold
intx CompileThreshold = 10000
intx Tier2CompileThreshold = 0
intx Tier3CompileThreshold = 2000
intx Tier4CompileThreshold = 15000

中间及汇编代码

-XX:+PrintAssembly:JVM安装反汇编适配器后,该参数使得JVM输出编译方法的汇编代码(Product版本需要"-XX:+UnlockDiagnosticVMOptions"选项,打开JVM诊断模式)
-XX:+PrintLIR:输出比较接近最终结果的中间代码表示,包含一些注释信息(用于C1,Debug版本)
-XX:+PrintOptoAssembly:输出比较接近最终结果的中间代码表示,包含一些注释信息(用于C2,非Product版本)
-XX:+PrintCFGToFile:将JVM编译过程中各个阶段的数据输出到文件中,而后用工具C1 Visualizer分析(用于C1,Debug版本)
-XX:+PrintIdealGraphFile:将JVM编译过程中各个阶段的数据输出到文件中,而后用工具IdealGraphVisualizer分析(用于C2,非Product版本)

JIT编译字节码大小

-XX:+DontCompileHugeMethods
-XX:HugeMethodLimit=8000

循环展开Loop Unrolling

java -XX:+UnlockDiagnosticVMOptions
-XX:-UseCompressedOops
-XX:PrintAssemblyOptions=intel
-XX:+PrintCompilation
-XX:CompileCommand=print,javamag.lu.LoopUnrolling::intStride1
javamag.lu.LoopUnrolling

java -XX:LoopUnrollLimit=1 XX:-UseBiasedLocking -XX:CompileCommand=print,com.zc.demo.compile.JMHSample.LockOptimization::test

逃逸分析Escape Analysis

根据逃逸分析的结果,进行优化的手段主要有三种:栈上分配、锁消除、标量替换。
-XX:+DoEscapeAnalysis手动开启逃逸分析
-XX:+PrintEscapeAnalysis 查看分析结果
-XX:+EliminateAllocations 开启标量替换
-XX:+EliminateLocks开启同步消除,或锁消除
-XX:+PrintEliminateAllocations 查看标量的替换情况

内联Inling

-XX:+UnlockDiagnosticVMOptions 解锁一些诊断性的虚拟机选项的参数。在 Java 虚拟机中,有一些高级和诊断性功能默认是被禁用的,以确保稳定性和安全性。
-XX:+PrintInlining观察编译器内联优化的信息

回边计数器编译OSR:

(CompileThreshold*((OnStackReplacePercentage-InterpreterProfilePercentage)/100))阈值计算公式
-XX:InterpreterProfilePercentage(解释器监控比率)默认值是33
-XX:OnStackReplacePercentage(OSR比率)client编译器中默认值是933
-XX:OnStackReplacePercentage(OSR比率)server编译器中默认值是140

IBMJDK

-Djava.compiler=jitc 启用jitc编译器
-Djava.compiler=j9jit<vm_version> 启用j9jit编译器
-Xjit:verbose={compileStart|compileEnd},vlog=/tmp/jit.log 记录JIT信息
-Xjit:{java/lang/Math.max*}(optLevel=noOpt) 调整优化级别
-Xjit:count=0 等待编译完成
-Xjit:exclude={java/lang/Math.max*}(count=0,optLevel=hot) 按类名排除

java -Xjit:verbose,optLevel=noOpt HelloWorld
a. scorching
b. veryHot
c. hot
d. warm <-- Initial compiling usually occurs at this level
e. cold
f. noOpt

命令和工具

命令

javap -v app.class javap查看字节码
javap -c app.class javap反编译
jstat -compiler 8963 jstat观察即时编译信息
jstat -compiler -t 8963 10000 30 jstat观察即时编译信息每10秒收集30次
jstat -gcmetacapacity 8963 jstat观察元数据区域信息
jinfo -flags 8963 jinfo观察当前赋值
jinfo -flag CICompilerCount 8963 jinfo观察编译器线程数量
jmap -histo 8963 | head -n30 jmap观察对象分布
jmap -dump:live,format=b,file=dump.hprof 8963 jmap生成dump

工具

Ideal Graph Visualizer:用于可视化展示C2即时编译器是如何将字节码转化为理想图,然后转化为机器码的。·
Client Compiler Visualizer[插图]:用于查看C1即时编译器生成高级中间表示(HIR),转换成低级中间表示(LIR)和做物理寄存器分配的过程。·
MakeDeps:帮助处理HotSpot的编译依赖的工具。·
Project Creator:帮忙生成Visual Studio的.project文件的工具。·
LogCompilation:将-XX:+LogCompilation输出的日志整理成更容易阅读的格式的工具。·
HSDIS:即时编译器的反汇编插件。

Ideal Graph Visualizer

在这里插入图片描述在这里插入图片描述

JITWatch

在这里插入图片描述
在这里插入图片描述

参考

基本功 | Java即时编译器原理解析及实践
https://tech.meituan.com/2020/10/22/java-jit-practice-in-meituan.html

Developers disassemble! Use Java and hsdis to see it all.
https://blogs.oracle.com/javamagazine/post/java-hotspot-hsdis-disassembler

Lessons from the field #6: IBM Java and OpenJ9 Just-In-Time Compiler Tuning
https://community.ibm.com/community/user/integration/blogs/kevin-grigorenko1/2021/06/30/lessons-from-the-field-6-ibm-java-and-openj9-just

JIT Problem Determination for IBM SDK using -Xjit
https://www.ibm.com/support/pages/jit-problem-determination-ibm-sdk-using-xjit

JIT 编译器如何优化代码
https://www.ibm.com/docs/zh/sdk-java-technology/8?topic=compiler-how-jit-optimizes-code

  • 16
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值