Java 8服务端应用偶发JVM崩溃疑似JIT导致,附gdb调用栈排查信息
JVM崩溃(疑似JIT导致)定位与解决步骤
第一步:先确认崩溃的实际触发点
你当前获取的调用栈是JIT编译线程的正常等待栈,并非崩溃触发栈,需要先获取以下核心信息:
- 查找JVM崩溃时自动生成的
hs_err_pid<进程号>.log文件,这是定位JVM崩溃的首选依据,重点查看以下字段:- 触发崩溃的信号类型(是
SIGSEGV段错误还是SIGABRT主动中止) Current Thread字段是否标记为C2编译器线程Current Compile Task字段,该字段会明确记录崩溃发生时JIT正在编译的类名、方法名,是定位触发JIT bug的核心依据
- 触发崩溃的信号类型(是
- 如果没有hs_err日志,回到gdb调试界面执行
info threads找到触发异常信号的线程,用thread <线程号>切换到对应线程后再执行bt指令,才能拿到崩溃的实际调用栈。
第二步:定位根因的实操方案
- 若hs_err日志中明确有正在编译的目标方法,先将该方法排除出JIT编译范围,添加JVM启动参数:
重启应用后观察是否还会崩溃,如果不再崩溃即可确认是该方法触发了JIT编译bug。-XX:CompileCommand=exclude,全类名路径,方法名 - 开启JIT编译日志辅助定位,添加JVM参数:
崩溃前最后一条编译日志对应的方法即为嫌疑目标,可针对性排查方法内是否存在特殊语法(如复杂lambda、大循环、高频自动装箱拆箱、反射调用等)触发了JIT优化的边界case。-XX:+LogCompilation -XX:LogFile=jit.log
第三步:问题解决方案,按优先级从高到低选择
- 优先选择:升级JDK版本
你当前使用的JDK 8u251是2020年发布的旧版本,Oracle JDK 8后续的小版本已经修复了数百个C2编译器的已知bug,升级到JDK 8u401以上的最新正式版本,90%以上的场景可以直接解决该问题,改造成本最低。 - 次选:排除嫌疑方法的JIT编译
如果暂时不能升级JDK,将定位到的触发JIT bug的方法加入编译排除列表,或者调整方法代码逻辑,绕开触发bug的代码片段即可。 - 兜底方案:关闭C2编译器
如果业务对峰值性能要求不高,可以直接添加JVM参数-XX:+TieredCompilation -XX:TieredStopAtLevel=1,仅开启C1即时编译,彻底规避C2编译器的所有bug,只会损失约10%~20%的峰值性能,稳定性更高。
内容的提问来源于stack exchange,提问作者zuoshengli
相关产品推荐
相关产品推荐

