要确认代码是否被jit优化编译,需启用-xx:+logcompilation获取xml日志,搜索方法签名并检查中type="pcmp"(标准编译)或type="osr"(栈上替换)、存在且level=4(c2编译),辅以-xx:+printcompilation实时验证。

要查看JIT编译日志并确认某段代码是否被成功优化编译(如C2编译器编译为机器码),需启用JVM的JIT编译日志输出,并结合日志内容定位目标方法。核心在于正确配置JVM参数、理解日志结构,以及识别关键标记。
启用详细JIT编译日志
使用 -XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation 启用XML格式的编译日志(推荐,信息最全)。该日志会输出到当前工作目录的 hotspot_pid
补充建议:
- 加 -XX:LogFile=/path/to/compile.log 指定日志路径,避免和应用日志混杂
- 加 -XX:+PrintCompilation 输出简明的实时编译摘要(控制台可见),适合快速筛查,但信息较粗略
- 若只关心特定类或方法,可配合 -XX:CompileCommand=print,.,例如:
-XX:CompileCommand=print,java.lang.String.indexOf
识别日志中目标方法是否被优化编译
在 hotspot_pid*.log 中搜索方法签名(如 java/lang/String.indexOf),重点关注 <task></task> 节点下的字段:
- type="osr" 表示这是栈上替换(On-Stack Replacement),说明方法已在解释执行中,因循环热点被OSR编译,属于优化编译
-
type="pcmp"(或旧版中的
compile_id非0且无 osr 标记)表示标准的首次编译(Tier 3 或 Tier 4),即方法入口被完整编译,是典型的优化编译结果 - 检查
<success></success>子节点是否存在且无failure属性 —— 有则代表编译失败(如代码太复杂、内存不足等) - 观察
level值:3 表示 C1 编译(客户端优化),4 表示 C2 编译(服务端深度优化),值越大通常优化程度越高
辅助验证:运行时检查编译状态
除日志外,还可通过JDK自带工具动态确认:
- 使用 jstat -compiler
查看整体编译统计(如已编译方法数、失败次数),但无法定位具体方法 - 搭配 jcmd
VM.native_memory summary 可辅助判断是否因CodeCache耗尽导致编译中止(常见于长期运行且大量动态生成类的应用) - 若启用 -XX:+PrintCompilation,控制台输出形如:
123 45 b 4 java.lang.String::indexOf (71 bytes)
其中 b 表示是后台线程编译,4 是编译级别,末尾字节数是生成的本地代码大小,有此行即代表已启动优化编译
常见干扰与注意事项
不是所有“看起来该编译”的方法都会被优化,需排除以下情况:
- 方法太小或调用频次未达阈值(默认C2触发阈值为10000次调用 + 100次回边,可通过 -XX:CompileThreshold 和 -XX:OnStackReplacePercentage 调整)
- 方法含不支持优化的字节码(如某些JNI调用、动态代理的桥接方法、或被 @HotSpotIntrinsicCandidate 排除的特殊情况)
- CodeCache空间不足(日志中可能出现
no space或not entrant状态),此时需增大 -XX:ReservedCodeCacheSize - 使用了 -XX:-TieredStopAtLevel=1 等禁用C2的选项,会导致只有C1编译,无深度优化










