GC调优
做GC调优,首先确定垃圾回收器,是选择低延迟的还是高吞吐量的回收器。
低延时的 CMS,G1,ZGC
高吞吐量的 ParallelGC
最快的 GC,是不发生 GC:
首先要考虑自己的代码,避免频繁发生GC。
考虑以下几点:
- 数据是不是太多?
- 数据表示是否太臃肿?
- 是否存在内存泄漏?
然后再考虑GC调优问题。
新生代调优:
新生代的特点
- 所有的 new 操作的内存分配非常廉价
- 每个线程都会在伊甸园中分配一个私有的区域TLAB(thread-local allocation buffer),避免多个线程同时创建对象,产生干扰。
- 死亡对象的回收代价是零
- 大部分对象用过即死
- Minor GC 的时间远远低于 Full GC
新生代内存大小的设置:
如果新生代内存过小,则会更密集的进行GC操作,影响程序的吞吐量。
如果新生代内存过大,则在单次GC操作中,时间会变慢,新生代内存设置过大,会导致老年代内存过小,引发Full GC。
因此,设置合适新生代内存大小,会对程序的吞吐量产生重要的影响。Oracle官方建议,将新生代内存大小设置为堆内存大小的 25%到 50% 之间。在新生代的GC中采用的是 标记复制算法,分为两个阶段,标记和复制,其中复制阶段占绝大部分时间。
理想的新生代内存大小为:【并发量 * (请求响应所占用的内存空间大小)】
幸存区的内存大小:要能保留【当前活跃对象+需要晋升对象】
如果幸存区空间过小,JVM会动态的调整晋升阈值,将没有达到寿命的对象存入老年代。
晋升阈值配置得当,让长时间存活对象尽快晋升
-XX:MaxTenuringThreshold=threshold (设置晋升阈值,达到后晋升入老年代)
老年代调优
以CMS为例,老年代的内存越大越好。
CMS在垃圾回收时,与用户线程并行运行,在进行垃圾回收时,用户线程会产生新的垃圾,称为浮动垃圾。如果浮动垃圾产生速度过快,来不及回收,那么将会导致CMS并发失败,进行Full GC,将会退化为 SerialOld,串行的老年代的垃圾回收器,效率就会变得特别低。
如果频繁发生Full GC,可以将老年代的内存调大一些(1/4 到 1/3 )。
-XX:CMSInitiatingOccupancyFraction=percent(设置老年代内存占比的值,达到这个值,将会进行垃圾回收),设置的时候要考虑为浮动垃圾预留出足够的内存,一般值设置为 75%-80%。