G1 垃圾回收器
G1回收器的设计思路
G1回收天然的适用于大内存服务器,首先G1将堆内存空间拆分为多个大小相等的Region块,Region的个数默认2048个,配置4g堆内存,每个region的大小就为2M。Region动态的属于老年代或者新生代,上一秒还是分配成新生代,经过回收以后空出来,下一秒有可能被分为老年代区。
在G1回收器这里已经不需要再提前设置新生代和老年代的大小,但是新生代仍区分Eden和Survivor区。大大降低了JVM参数的调优复杂度,只需配置-XX:MaxGCPauseMillis=n(ms),设置最大GC停顿时间,剩下的交给G1回收器。G1会自动追踪每个region可以回收的大小和预估的时间,最后在真正垃圾回收的时候,尽量把垃圾回收控制在设置的时间范围内,在有限的时间内回收更多的对象。
G1的核心调优参数
G1收集器自身已经有一套预测和调整机制了,因此我们首先的选择是相信它,即调整-XX:MaxGCPauseMillis=N参数,这也符合G1的目的——让GC调优尽量简单!同时也不要自己显式设置新生代的大小(用-Xmn或-XX:NewRatio参数),如果人为干预新生代的大小,会导致目标时间这个参数失效。
针对-XX:MaxGCPauseMillis来说,参数的设置带有明显的倾向性:调低↓:延迟更低,但MinorGC频繁,MixGC回收老年代区减少,增大Full GC的风险。调高↑:单次回收更多的对象,但系统整体响应时间也会被拉长。
针对InitiatingHeapOccupancyPercent来说,调参大小的效果也不一样:调低↓:更早触发MixGC,浪费cpu。调高↑:堆积过多代回收region,增大FullGC的风险。


浙公网安备 33010602011771号
rpc在网络上传输数据,lpc本地传输
垃圾回收器的选择
1.吞吐量还是响应时间
首先引入两个概念:吞吐量和延迟时间
吞吐量 = CPU在用户应用程序运行的时间 / (CPU在用户应用程序运行的时间 + CPU垃圾回收的时间)
延迟时间 = 平均每次的GC的耗时
通常,吞吐优先还是响应优先这个在JVM中是一个两难之选。堆内存增大,GC一次能处理的数量变大,吞吐量大;但是GC一次的时间会变长,导致后面排队的线程等待时间变长;相反,如果堆内存小,GC一次时间短,排队等待的线程等待时间变短,延迟减少,但一次请求的数量变小(并不绝对符合),无法同时兼顾。吞吐优先VS响应优先,是JVM调优过程中需要权衡的核心问题。
2.垃圾回收器设计上的考量
垃圾回收器的底层实现机制非常复杂,但是设计者的设计目标无外乎以下几条:
JVM在GC时不允许一边垃圾回收,一边还创建新对象(就像不能一边打扫卫生,还在一边扔垃圾)。
基于第一条GC时需要一段Stop the world的暂停时间,而STW会造成系统短暂停顿不能处理任何请求;
新生代收集频率高,性能优先,常用复制算法;老年代频次低,空间敏感,避免复制方式。
所有垃圾回收器的设计目标都是要让GC频率更少,时间更短,减少GC对系统影响!
目前主流的垃圾回收器配置是新生代采用ParNew,老年代采用CMS组合的方式,或者是完全采用G1回收器,从未来的趋势来看,G1是官方维护和更为推崇的垃圾回收器。
业务系统,延迟敏感的推荐CMS;大内存服务,要求高吞吐的,采用G1回收器!下面单独就两款回收器的工作机制和适用场景进行一下说明:
CMS垃圾回收器的工作机制
CMS主要是针对老年代的回收器,新生代的采用ParNew回收器,工作流程就是上文提到的经典复制算法,在三块区中进行流转回收,只不过采用多线程并行的方式加快了MinorGC速度。老年代是标记-清除,默认会在一次FullGC算法后做整理算法,清理内存碎片。
优点:并发收集、主打“低延时” 。在最耗时的两个阶段都没有发生STW,而需要STW的阶段都以很快速度完成。
缺点:1、消耗CPU;2、浮动垃圾;3、内存碎片
适用场景:重视服务器响应速度,要求系统停顿时间最短。