关于Old GC在上次垃圾回收后立即启动的异常技术咨询
分析Old区回收后立即触发GC的问题
咱们先从你提供的GC日志入手,先把日志格式化出来方便分析:
2018-04-15T13:07:30.028+0530: 51251.379: [GC2018-04-15T13:07:30.028+0530: 51251.379: [ParNew: 277743K->6502K(306688K), 0.0103550 secs] 3494143K->3223365K(4160256K) icms_dc=0 , 0.0104470 secs] [Times: user=0.03 sys=0.01, real=0.01 secs] 2018-04-15T13:07:30.133+0530: 51251.485: [GC2018-04-15T13:07:30.134+0530: 51251.485: [ParNew: 279142K->7017K(306688K), 0.0116990 secs] 3496005K->...
日志关键信息解读
这两次都是**ParNew(新生代并行回收器)**触发的GC,间隔仅100毫秒左右,属于连续触发的情况:
- 第一次GC:新生代几乎被填满(277743K / 306688K),回收后仅剩6502K;整个堆从3494M降到3223M,耗时仅0.01秒,说明回收效率没问题,但对象填充速度太快。
- 第二次GC:间隔100毫秒后,新生代又被填满到279142K,再次触发回收。
可能的原因
- 对象分配速率过高:应用在短时间内快速创建大量临时对象(比如批量任务、突发流量下的请求处理,或者代码里存在循环创建大对象/字符串拼接这类操作),刚回收完的新生代瞬间被填满,立刻触发下一次GC。
- 新生代空间配置过小:你的新生代仅306M,而整个堆是4160M,新生代占比不到8%,空间太小导致对象很快就填满了新生代,频繁触发GC。
- 对象过早晋升到老年代:如果
-XX:MaxTenuringThreshold设置过低,或者新生代的Survivor区不够大,导致短生命周期对象提前晋升到老年代,占用老年代空间,间接压缩了新生代的可用空间,加剧GC频率。
解决建议
- 排查对象创建热点:用JProfiler、VisualVM这类工具分析对象分配速率,定位到快速创建大量对象的代码段,比如优化字符串拼接为
StringBuilder、复用对象池、避免循环内创建大对象等。 - 调整新生代内存大小:通过
-Xmn参数直接指定新生代大小,或者调整-XX:NewRatio(比如设置为2,让新生代占堆的1/3),给新生代更多空间,减少GC触发频率。 - 检查内存泄漏风险:确认是否存在长生命周期对象持有短生命周期对象引用的情况,导致本该回收的对象晋升到老年代,占用堆空间。可以用堆dump分析老年代的对象组成。
- 优化GC参数:调整
-XX:MaxTenuringThreshold,适当提高对象晋升老年代的年龄阈值,让短生命周期对象在新生代多回收几次再晋升;同时检查是否开启了不必要的GC相关参数,避免干扰GC触发逻辑。
内容的提问来源于stack exchange,提问作者user2757415
相关产品推荐
相关产品推荐

