服务重启后前几小时正常,第二天接口耗时涨了 3 倍,日志里出现 CodeCache is full. Compiler has been disabled,jconsole 显示 Code Cache 使用率 100%。日志里能对上时间点,这种反而好排。

JIT 编译后的机器码放在 CodeCache,默认上限 240MB。动态生成大量类或方法很多时会被填满,编译器停止工作,热点方法退回解释执行。这一点先确认清楚,后面就不用反复试。

java -XX:ReservedCodeCacheSize=512m -XX:+UseCodeCacheFlushing \
  -XX:+PrintCodeCache -jar app.jar
jcmd 21455 Compiler.codecache

「CodeCache 满」排查到最后往往是很小的一处差异,前面那些复杂猜测可以先放一放。偶发问题先统计频率,一小时几次和一天一次,查法完全不同。

改完顺手把文档补一句,省得下次自己重新推一遍。监控和日志的时间要对上,时区不一致会多绕很大一圈。

临时改动用注释写上日期和原因,过两周自己都记不清为什么这么写。动手前把原文件复制一份带时间戳,出问题立刻换回去,比现场分析快得多。

处理上按这个顺序:用 -XX:+PrintCodeCache 或 jcmd Compiler.codecache 看实际占用;把 ReservedCodeCacheSize 调到 512m;检查是否有大量动态代理或脚本生成新方法;开启 -XX:+UseCodeCacheFlushing 让冷代码能被清掉。

结果对不对很好判断,Code Cache 使用率稳定在 60% 以下 日志里不再出现 Compiler has been disabled。

作者 9823189