一、jvm error日志
今天碰到JVM莫名其妙执行一段时间后,就崩溃的问题,通过上面的日志,信息有:
CompilationPolicy::can_be_compiled
文件在./hotspot/src/share/vm/runtime/compilationPolicy.cpp找到对应的方法:can_be_compiled
bool CompilationPolicy::can_be_compiled(methodHandle m, int comp_level) {
// allow any levels for WhiteBox
assert(WhiteBoxAPI || comp_level == CompLevel_all || is_compile(comp_level), "illegal compilation level");
if (m->is_abstract()) return false;
//如果方法的字节码长度超过HugeMethodLimit,不适用JIT编译
if (DontCompileHugeMethods && m->code_size() > HugeMethodLimit) return false;
....
}
DontCompileHugeMethods & HugeMethodLimit 的定义在./hotspot/src/share/vm/runtime/globals.hpp
product(bool, DontCompileHugeMethods, true,
"don't compile methods > HugeMethodLimit")
develop(intx, HugeMethodLimit, 8000,
"don't compile methods larger than this if "
"+DontCompileHugeMethods")
从上面的定义可知,如果方法的字节码长度超过8000byte(差不多2500行) & DontCompileHugeMethods =true,不会执行jit编译,如果想改变这个条件,即增加VM参数”-XX:-DontCompileHugeMethods”来强迫JVM编译大方法。但是不建议这么做,因为一旦Code Cache满了,HotSpot会停止所有后续的编译任务,虽然已编译的代码不受影响,但是后面的所有方法都会强制停留在纯解释模式。
C1 C2
日志里出现这2个关键字,需要联想到jit( just in time),也就是即时编译编译器。这里涉及到的知识点是JIT编译器在运行时的两种模式:JVM Server 模式与 client 模式,以及分层编译的策略。
程序为了达到启动速度和执行效率的平衡,虚拟机采用分层编译的策略,包括:
第0层:解释执行,解释器不开性能监控;
第1层:C1编译,将字节码编译成本地代码,进行简单、可靠的优化,使用的是一个代号为 C1 的轻量级编译器,虚拟机运行参数里有-client;
第2层:C2编译,也是将字节码编译为本地代码,启动时,速度较慢,但是一旦运行起来后,性能将会有很大的提升。由于采用相对重量级代号为 C2 的编译器,C2 比 C1 编译器编译的相对彻底,服务起来之后,性能更高。
实施分层编译后,Client Compiler和Server Compiler 将会同时工作,许多代码都可能会多次编译,C1获取更高的编译速度,用C2获取更好的编译质量,在解释时候的时候也无须再承担收集性能监控信息的任务。
通过java -version查看JIT编译的模式
mixed mode是混合模式,使用-Xint -Xcomp改变执行方式解释模式、编译模式。所谓解释模式,即不使用jit,直接由解释器执行所有字节码,执行效率不高;编译模式即将所有的字节码无论执行频率都编译为机器码,完全没有必要,所以采用混合模式(默认)即可。
二、JIT原理
JVM读取.class文件之后,会交给JIT,其根据是否是热点代码判断可否将该方法优化成机器码。