g1 mixed gc优化核心是精准识别该回收的老年代region,关键在调整ihop至30%~35%、降低g1mixedgclivethresholdpercent至65%、限制g1oldcsetregionthresholdpercent为10%,并抑制无效晋升。

针对长期存活变量优化G1 Mixed GC,核心不是“强行提前回收”,而是让G1更准确识别哪些老年代Region确实该回收、哪些该保留,避免无效扫描与过早晋升。关键在于控制混合回收的触发时机、范围和对象存活率判断逻辑。
精准触发Mixed GC:避免过早或过晚
长期存活变量堆积在老年代,但G1不会等老年代快满才回收——它靠堆占用率动态决策。默认IHOP(InitiatingHeapOccupancyPercent)=45%往往偏保守:
- 设为30%~35%可让Mixed GC更早介入,赶在大量长期对象稳定驻留前清理掉已死亡的Region;
- 但低于30%易导致Mixed GC过于频繁,反增开销(某金融系统调至30%后吞吐量降15%);
- 建议结合GC日志中
mixed gc的触发堆占比(initiating occupancy字段)反推真实阈值,再微调。
收缩回收范围:聚焦真正可回收的老年代Region
Mixed GC默认会扫描所有满足条件的老年代Region,但长期存活变量所在的Region往往很“干净”(存活率高),扫了白扫。可通过两个参数收紧范围:
- G1MixedGCLiveThresholdPercent=65:只回收存活对象≤65%的Region(默认85%)。对含大量长期变量的系统,调低该值能跳过高存活Region,减少无谓扫描;
- G1OldCSetRegionThresholdPercent=10:限制每次Mixed GC最多选老年代Region总数的10%(默认无上限),防止单次回收压力过大。
抑制无效晋升:从源头减少长期变量对老年代的污染
很多“长期存活变量”其实是本不该进老年代的——比如缓存对象被弱引用管理后仍意外强引用,或大集合未分批处理导致直接分配到老年代:
- 用WeakReference/SoftReference包装缓存,配合
ReferenceQueue及时清理; - 批量操作改用
Stream.iterate().limit(n)分页,避免单次加载万级List撑爆Survivor区; - 检查
ThreadLocal使用,未remove()会导致Value对象长期滞留老年代(尤其在线程池场景)。
验证是否生效:盯住三个关键指标
调优后不看日志等于没调。重点关注GC日志中的:
-
Mixed GC耗时:是否稳定在
MaxGCPauseMillis目标内(如100ms),且波动小; -
Old CSet大小:日志中
old regions数字是否随调优下降(说明筛选更准); -
晋升失败(Evacuation Failure):若出现,说明Survivor区或老年代预留空间不足,需调
G1ReservePercent(建议10%~20%)。










