-XX:ReservedCodeCacheSize 专用于设定JVM代码缓存最大预留容量,存放JIT编译的机器码等,不参与GC、独立于堆/元空间;设小会导致编译禁用、性能骤降,需据实测峰值+30%配置,并关注最大连续空闲块防碎片。

这个参数直接决定 JVM 能给 JIT 编译出的机器码划多大“地盘”。地太小,编译器干到一半就收工;地太大,又容易卡住、浪费、甚至拖慢自己。
它管什么、不管什么
-XX:ReservedCodeCacheSize 设置的是 Code Cache 区域的**最大预留容量**,专用于存放 JIT 编译后的本地机器码(nmethod)、适配器(adapter)、桩代码(stub)等。它和堆内存、元空间、直接内存都分开管理,GC 不动它,jstat -gc 也查不到它。
它不控制:编译是否开启、编译层级(C1/C2)、方法是否够“热”、类加载行为,也不影响 GC 策略本身。
设小了会怎样
一旦达到设定上限,JVM 就会立刻停掉所有新方法的 JIT 编译,日志里明确打出 CodeCache is full. The compiler has been disabled。这不是变慢,是硬关闸:
- 新上线接口、Lambda 表达式、Spring CGLIB 代理方法全部只能解释执行,性能跌 5–10 倍
- 已编译的老代码还能跑,但新增逻辑完全失去优化机会
-
jstat -compiler中Compiled字段停滞,Failed持续上涨,Invalid数值变大 - CPU 使用率可能在几分钟内跳升 30%~50%,P99 延迟突变,但堆和 GC 日志看起来一切正常
怎么设才合适
不能拍脑袋定 512m 或 1g,得看真实用量再加余量:
- 用
jstat -codecache <pid> 1000 5</pid>每秒采样 5 次,抓高峰Used值 - 按峰值上浮 30% 设定,比如峰值 180MB →
-XX:ReservedCodeCacheSize=256m(单位必须带 m/M) - 容器部署时,要把这部分内存算进总预算,它属于 off-heap,不受 -Xmx 控制
- JDK 8u202 之前默认仅 48MB,老服务风险极高;JDK 11+ 默认 240MB,但仍需实测
碎片化比打满更隐蔽
有时候 jstat -codecache 显示 Used 才 70%,却已频繁失败——问题出在 largest_free_block 太小。JIT 编译需要连续内存块存一个 nmethod,哪怕总空闲还有 50MB,若最大连续空闲只有 2KB,也会提前禁用编译器。
排查方式:
- 加
-XX:+PrintCodeCache(仅调试),盯largest_free_block是否长期低于 1MB - 用
jcmd <pid> VM.code_cache</pid>查各段分布和最大空闲块 - 大量反射调用、Lambda、动态代理会推高
adapter_count,这类代码回收难度大,易成碎片源


















