codecache满导致jit被硬性禁用而非缓慢降级:日志出现“codecache is full. the compiler has been disabled”等即熔断,jstat -compiler显示compiled停滞、failed激增,jcmd vm.code_cache可定位segment级碎片化瓶颈。

CodeCache 满不是性能缓慢下滑,而是 JIT 编译器被硬性禁用——所有新方法(包括 Spring 代理、Lambda、反射调用)全部退回到解释执行,性能通常下降 5–10 倍。关键在于别靠猜测,要用 JVM 自带工具交叉验证编译状态是否已中断。
看日志:找最直接的熔断证据
检查 JVM 启动后 stdout/stderr 或 GC 日志中是否出现以下任一原样字符串(注意大小写和空格):
- CodeCache is full. The compiler has been disabled.
- hotspotcompilequeue: disabled
- OutOfMemoryError: requested N bytes for Chunk::new
只要出现其中一条,就代表 JIT 已全局停摆,不是临时降级,也不会自动恢复,必须重启或手动刷新(前提是未关闭 -XX:+UseCodeCacheFlushing)。
查运行时状态:jstat -compiler 是核心指标
仅看内存使用率会误判。真正反映 JIT 是否存活的是编译行为本身:
- 运行
jstat -compiler <pid></pid>,持续观察:
→ Compiled 字段长期停滞不涨(比如 5 分钟内无变化)
→ Failed 字段每分钟增长超 50 次(说明编译请求不断被拒)
→ Invalid 数值明显上升(表示已有编译产物被驱逐或失效) - 注意:
jstat -gccapacity中的 CCSU ≥ CCMX 且 CCS 不再增长,是辅助佐证,但不能替代 -compiler 输出。
定位碎片化:jcmd VM.code_cache 比 jstat -codecache 更准
有时 Used 还没到 Max,但 JIT 已停——这是碎片化导致“有空间却无法分配连续块”:
- 运行
jcmd <pid> VM.code_cache</pid>(JDK 11+ 支持),查看三段 CodeHeap:
→ NonNMethodCode(stubs/adapters)
→ ProfiledCode(带 profile 的方法)
→ NonProfiledCode(不带 profile 的方法)
若其中某一段 used == max_used,或 largest_free_block ,即为实际瓶颈。 -
jstat -codecache <pid></pid>只给总览,看不出哪一段卡死;而 jcmd 能暴露 segment 级满载,这才是长期运行微服务的真实隐患。
排除干扰:确认不是 GC 或线程问题
CodeCache 耗尽的典型特征是“CPU 高、响应慢、堆内存和 GC 正常、线程堆栈分散”:
- 用
jstat -gc <pid></pid>确认 YGC/FGC 频率稳定,GCT 不突增; - 用
jstack <pid></pid>查看线程状态,不会集中阻塞在锁或 IO,而是大量线程处于 RUNNABLE 但业务处理变慢; - 如果
jstat -compiler显示异常,但 GC 和线程都正常,基本可锁定 CodeCache。










