JVM - GC 问题分析常用两大指标
在分析 JVM 存在的问题时,最常用的两个指标就是:
分配速率
提升速率
下面就来分别介绍一下这两个指标。
分配速率
分配速率表示单位时间内分配的内存量。通常使用 MB/Sec 作为单位。
计算方式为:上一个 GC 之后的年轻代使用量 减去 下一次 GC 之前年轻代使用量,再除以两次 GC 之间的时间,即可得出分配速率。
高分配速率:当 JVM 中当分配速率过高,就会严重影响程序的性能,可能会导致巨大的 GC 开销。
高分配速率的影响:分配速率影响着 Eden 区的使用,如果 Eden 区过小,分配速率高,就会出现大量的 GC ;增大年轻代(即增大 Eden 区),虽然不能降低分配速率,但能够减少 Minor GC 的次数,而且如果每次 GC 只有少量对象存活,minor GC 的暂停时间就不会明显增加。
分配速率的三种情况:
正常系统:分配速率较低,回收速率健康
内存泄露:分配速率持续大于回收速率,最后会导致 OOM
性能劣化:分配速率较高,回收速率能够维持,系统处于亚健康状态。
应对高分配速率的手段
调高 年轻代 的大小,降低 Minor GC 的次数
优化代码,降低分配速率。
提升速率
提升速率,用于衡量单位时间内从年轻代晋升到老年代的数据量。通常使用 MB/Sec 作为单位。
过早提升
JVM 会将长时间存活的对象从年轻代晋升到老年代,根据分代假设,如果出现大对象,使得年轻代无法容纳,就会分配到老年代中,也就是说,老年代中不仅有存活时间长的对象,也有存活时间短的对象。
过早提升就是指,存活时间不够长的对象被晋升到了老年代。
过早提升的影响:由于 major GC 不是为频繁回收而设计的,但由于过早提升,Major GC 也要清理这些生命周期短的对象,这就会导致 GC 暂停时间过长,影响系统的吞吐量。
过早提升的表现
短时间内频繁执行 Full GC
每次 Full GC 后老年代的使用率都变得很低,变回到 10%~20%,或者更低。
提升速率解决分配速率。
应对手段
过早提升,本质上是年轻代放不下只需暂存的数据,因此,解决手段就是:让年轻代放得下暂存的数据,主要有两种方案:
增加年轻代大小。
减少每次批处理的数据量。
选用哪种方案,取决于业务需求。如果业务逻辑不允许减少批处理的数据量,那么就只能增加内存,或者重新设置年轻代的大小。如果都不可行,只能优化数据结构,减少内存消耗。
评论