JIT

一、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,其根据是否是热点代码判断可否将该方法优化成机器码。

猜你喜欢

转载自my.oschina.net/u/2302503/blog/1815644
JIT