-XX:+PrintCompilation 是 JVM 轻量级 JIT 编译观测工具,实时输出方法编译时机、等级(0–4)、耗时及内联决策;等级逐级提升(1→3→4),不可跳级,支持精准过滤与线上低开销追踪。
-XX:+PrintCompilation
是 JVM 提供的轻量级 JIT 编译观测工具,能实时输出方法被 C1/C2 编译器编译的时机、编译等级(compilation level)、耗时及内联决策等关键信息。它不依赖外部 profiler,开销极低,适合线上核心路径的编译行为追踪。
理解编译等级(Level)含义
JVM 中 JIT 编译等级从 0 到 4(HotSpot 默认),不同等级对应不同优化强度和触发条件:
Level 0
:解释执行,未编译
Level 1
:C1 编译(客户端模式),基础优化(如去虚拟化、简单内联),启动快、开销小
Level 3
:C1 + 少量 profiling,用于中等热点方法
Level 4
:C2 编译(服务端模式),深度优化(循环展开、逃逸分析、向量化等),需足够 warmup 和 profile 数据
Level 5
(部分 JDK 版本):Graal JIT 或特定平台专用编译器,非默认启用
注意:方法不会“跳级”编译,而是按热度逐步升级(如 1 → 3 → 4),且可能因去优化(deoptimization)回落到低等级或解释执行。
精准过滤核心方法的编译日志
直接开启
会产生海量日志,需结合其他参数聚焦目标:
加
查看内联决策,确认关键方法是否被内联进更高层热点方法
用
精确打印指定方法的每次编译详情(含字节码行号、内联栈)
配合
排除干扰类(如监控打点逻辑)
添加
输出 XML 格式日志,后续可用
可视化分析演变路径
识别关键演变信号与典型问题
观察日志中同一方法多次编译记录,重点关注以下模式:
等级停滞
:长期卡在 Level 1/3,未升到 4 → 检查方法是否含未支持操作(如大 switch、反射调用、JNI)、是否被频繁去优化(看 deopt 日志)
反复编译/去优化
:同一方法短时间内多次出现 “made not entrant” + “made zombie” → 存在类型不稳定(如多态分派未收敛)、profile 失效或 ClassLoader 卸载
编译耗时突增
:Level 4 编译耗时 >500ms → 方法过大或含复杂控制流,可拆分或用
(JDK 10+)临时规避
内联失败提示
:日志中出现 “too big”、“hot method too large”、“not inlineable” → 方法体超阈值(-XX:MaxInlineSize / -XX:FreqInlineSize),或含 try-catch/同步块影响判断
线上使用建议与注意事项
该参数本身无显著性能损耗(单次编译仅纳秒级日志开销),但日志写入可能成为瓶颈:
避免直接输出到 stdout/stderr,改用
(JDK 10+ 统一日志框架)
生产环境建议只对关键服务实例开启,持续时间控制在 10–30 分钟,覆盖完整请求周期(含预热)
注意 JDK 版本差异:JDK 8 使用
,JDK 9+ 推荐统一用
,语义更明确
结合
查看全局编译统计(已编译方法数、失败数、队列长度),辅助判断是否编译器过载
不复杂但容易忽略:编译等级演变反映的是运行时热点真实分布,比静态代码分析更可信——它告诉你“哪些路径真正重要”,而非“你以为重要”。
-XX:+PrintCompilation-XX:+PrintInlining-XX:CompileCommand=print,*YourService.doWork-XX:CompileCommand=exclude,*MetricsReporter.*-XX:+UnlockDiagnosticVMOptions -XX:+LogCompilationjitwatch@CompilerControl(Exclude)-Xlog:compiler=info:file=compile.log:time,tags:filecount=5,filesize=10M-XX:+PrintCompilation-Xlog:compilerjstat -compiler 