You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java 21代码缓存已满却未触发Full GC的原因及参数咨询

问题原因

你指出的JDK-8290025正是导致该行为变化的核心原因,这个JDK变更彻底调整了Code Cache垃圾回收的触发逻辑,尤其针对Serial GC场景:

  • Java 17及更早版本中,Code Cache达到阈值时会主动触发Full GC来清理失效的编译代码(nmethod);
  • 升级到Java 21后,Code Cache的清理被绑定到堆的Full GC周期——只有当堆内存(尤其是老年代)触发Full GC时,才会顺带执行Code Cache清理。你的服务老年代占用率极低,没有堆层面的Full GC触发条件,因此Code Cache即便填满也不会主动触发Full GC。

你尝试的-XX:SweeperThresholdStartAggressiveSweepingAt等参数未生效,是因为这些参数仅控制Code Cache的激进清理策略,无法绕过21版本新增的“依赖堆Full GC触发”的逻辑——没有堆Full GC的信号,这些参数无法单独驱动Code Cache清理。

可尝试的JVM参数

针对Serial GC下的Code Cache清理问题,推荐尝试以下参数:

  1. 让Code Cache清理与Young GC绑定
    添加参数:-XX:+CodeCacheFlushingOnYoungGC
    该参数会让JVM在每次Young GC时尝试清理Code Cache,无需等待Full GC,适配你服务老年代无压力的场景,能定期清理失效编译代码。

  2. 调整Code Cache阈值触发逻辑

    • XX:CodeCacheMinFreeSpace=2m:设置Code Cache的最小空闲空间阈值,当空闲空间低于该值时触发清理尝试;
    • -XX:CodeCacheExpansionSize=1m:减小Code Cache的扩容步长,避免一次性占用过多空间,让阈值触发更敏感。
  3. 启用分段Code Cache(长期推荐)
    Java 21默认支持分段Code Cache(分为NonNMethod、Profiled、NonProfiled三个独立区域),不同区域可独立清理,降低整体填满概率。如果你的服务当前使用非分段模式,可添加参数开启:

    -XX:+SegmentedCodeCache
    -XX:ReservedCodeCacheSize=40m
    -XX:NonProfiledCodeCacheSize=20m
    -XX:ProfiledCodeCacheSize=15m
    
  4. 临时验证用:强制定期Full GC(不推荐生产)
    若需快速验证Code Cache是否能在Full GC时被清理,可添加-XX:+ExplicitGCInvokesConcurrent并在代码中定时调用System.gc(),但这会引入不必要的Full GC开销,仅用于排查问题。

额外排查技巧
  • 用jcmd <pid> Compiler.codecache命令查看Code Cache各区域的占用明细,确认是哪类代码(如Profiled方法)占满缓存;
  • 调整-XX:CompileThreshold降低JIT编译触发阈值,减少临时代码对Code Cache的占用。

内容的提问来源于stack exchange,提问作者Jesper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 02:35:54