核心在于主动监控与合理配置:通过jstat -codecache监控used/max比值(超90%即危险)、jstat -compiler观察failed增长,按峰值×1.3设置reservedcodecachesize(如峰值192m→256m),禁用非必要动态能力,并启用-xx:+useg1gc降低碎片。

预防 JIT 代码缓存清理导致的性能退化,核心在于避免缓存被填满、碎片化或被动驱逐,而不是等它“快满了再救”。变量执行退化(如热点函数突然回退到解释执行)往往不是代码写得不好,而是 JIT 编译产物无法驻留或持续生效。
监控 Code Cache 使用率,别等失败才报警
缓存溢出前没有明显 GC 日志或堆异常,jstat -gc 看不出问题。必须主动查:
-
jstat -codecache
:重点关注 Used 与 Max 的比值,持续高于 90% 就已危险 -
jstat -compiler
:若 Failed 字段持续增长、Compiled 停滞,说明 JIT 已停摆 -
jinfo -flag ReservedCodeCacheSize
:确认当前限制值,老 JDK(如 8u192)默认仅 48M,极易触发降级
预留余量 + 合理设上限,不盲目堆大内存
ReservedCodeCacheSize 不是越大越好。设太大可能因 mmap 分配失败直接启动失败,尤其在容器中:
- 先用 jstat -codecache
1000 10 观察 10 秒内峰值用量 - 按峰值 × 1.3 设置,例如峰值 192M → 设为 -XX:ReservedCodeCacheSize=256m(单位必须小写 m)
- OpenJDK 11+ 默认 240M 可作起点;JDK 8 建议至少调至 256m,避免默认 48M/96M 坑
减少无效编译与动态膨胀源
UseCodeCacheFlushing 只能清理“冷代码”,对 Spring AOP 代理、Groovy 脚本、热 redefine 等持续注入型膨胀无效:
- 禁用非必要动态能力:关闭开发期热部署插件、限制 eval/exec 使用频次
- 收敛 Lambda 和匿名类生成:避免在循环内反复创建 Function 实例,改用静态方法引用
- 对高频反射调用(如 JSON 序列化)启用白名单缓存,减少 JIT 频繁重编译压力
配合运行时策略,延长有效编译生命周期
JIT 编译代码不是永久驻留,但可通过配置延缓失效:
- 启用 -XX:+UseG1GC:G1 对 Code Cache 元数据管理更友好,降低碎片概率
- 避免频繁 full GC 或 CMS 并发模式:某些 GC 策略会强制刷新 Code Cache 中的 profiled 方法
- 容器环境加 --memory-limit 时,把 ReservedCodeCacheSize 纳入预算,防止因 cgroup 内存回收误杀 JIT 区域










