本文中无特殊说明,均为Hotspot虚拟机。
JVM中编译的定义
前端编译器
这个没什么好讲的,是离我们最近,最先认知的,最常见的是javac 编译器,它负责将".java"后缀文件,编译成".class"的字节码文件,最终供JVM运行。
扩展:在这个编译的过程中,有一个插入式注解使用器,可以让我们在编译的过程中去检查(类,方法,注解,字段等),我们可以利用这个使用器自定义实现某些功能。(比如:Lombok,MapStruct框架等等)
后端编译器
主要是针对于程序运行时期,将字节码解释生为本地机器码的过程,它的编译速度与结果质量高低,也是衡量JVM性能的重要指标。
解释器
逐行读取字节码指令,翻译为为机器码进行执行,不需要对代码进行预先的编译。JAVA程序最初就是通过解释器进行解释执行的。
java -Xint (强制解释模式)
编译器
即时编译器
在逐步解析的过程中,JVM发现某个方法或代码块运行特别频繁,我们暂且把它称为“热点代码”,那为了提高这些热点代码的效率,我们提前把这部分代码编译为机器码,后面就可以直接运行已经编译好的机器码。所以它是一种运行时的编译器(也叫即时编译器JIT),它是在运行的过程中对字节码进行编译。
常见的JIT编译器有:C1,C2,Graal等编译器。 java -Xcomp (强制编译模式)
提前编译器
指的是运行前就将字节码编译为了本地代码,这样程序实际运行时可以直接执行机器码,占用内存也少,效率也快,但是会屏蔽了一次编译到处运行的初衷,如果你确定了操作系统,可以试试(比如Android)。但尽管如此,也不是绝对的高性能(感兴趣可以关注下Jaotc,关注CDS缓存),有些情况还是有劣处(性能分析制导优化、激进预测性优化、链接时优化,这里就不阐述了防止文章过长,读者可自学查阅相关资料)
常见的提前编译器有:AOT,Jaotc,ART等编译器。 java -Xcomp (强制编译模式)
混合模式
混合模式是指结合解释器和编译器,它们相辅相成的配合性工作,其目的是充分利用解释器启动速度快,编译器执行效率高的特点,以达到较好的性能平衡。 比如: 程序启动时,采用解释器来执行字节码,这样程序能快速运行起来,在运行起来的过程,通过监控热点代码,对热点代码编译为机器码(此外,解释器也可以作为编译器激进优化的逃生门,因为编译大多数情况下都能提升运行速度,但是当激进优化的假设不成立,如加载了新类,类型继承结构出现变化,出现“罕见陷阱”时还可以通过解释器状态继续运行)。
java -Xmixed 混合模式
调优
主要列出我们实战中,常用的JVM调优参数。
-client
使用C1编译器,编译速度快。
-server
使用C2编译器,会做更多的编译时优化,编译时长会长于C1,但是编译后的代码质量高于C1。
-XX:+TieredCompilation
开启分级编译,如果使用该参数,必须使用-server模式,如果是-client模式就不会启用。(分级编译是一种编译策略,比如程序刚运行采用解释方式运行,随着代码被频繁调用,采用C1编译,它主要从OSR(栈上替换)、方法内联、去虚拟化等简单优化,编译很快;如果代码依然编译很频繁,使用C2,C2编译会包含梗复杂的优化,如OSR(栈上替换)、逃逸分析、循环展开等深度优化)
-XX:ReserverCodeCacheSize
代码缓存大小,在缓存用完后,不会抛OOM,而是停止JIT编译,后续未编译的解释执行,所以性能会有影响。代码缓存空间清理也是在系统GC完成
-XX:CompileThreshold=n
函数调用N次视为热点代码
-XX:+PrintCompilation
打印即时编译日志
-XX:CIComplierCount=n