G1 收集器
发布网友
发布时间:2024-10-23 20:56
我来回答
共1个回答
热心网友
时间:8分钟前
G1收集器是一款专为服务器端运行设计的垃圾收集器,针对多核处理器和大内存机器优化。它旨在提供高吞吐量的同时,将垃圾回收停顿时间控制在较短范围内。G1收集器在长期规划中以替代CMS收集器为目标,相比CMS,它具有以下优势:
- G1收集器通过使用regions代替细粒度的空闲列表进行内存分配,有效减少内存碎片的产生。
- G1收集器的停止时(Stop The World,STW)时间更可控,通过预测机制,用户可以定义预期的停顿时间。
G1收集器在内存布局上采用了全新设计,堆内存被划分为大小相等的heap region,一般有2000多块,这些region在逻辑上是连续的,可以作为新生代、幸存区和老年代使用。
在GC过程中,G1收集器会执行全局并发标记(concurrent global marking phase)过程,以确定堆里对象的存活状态。标记完成之后,G1收集器会优先回收垃圾多的region,从而最大化释放空间。这种垃圾回收方式被称为G1(Garbage-First),因为优先回收可能充满垃圾的对象。
G1收集器将收集和压缩活动集中在堆中可能充满可回收对象的区域,并通过停顿预测模型来满足用户定义的停顿时间目标,同时根据指定的停顿时间目标选择要收集的region数量。
需要注意的是,G1收集器不是实时收集器,它能够以较高的概率满足设定的停顿时间目标,但并非绝对确定。收集器会基于以前收集的数据,估算出在用户指定的目标时间内可以收集多少个region。
在G1收集器中,新生代垃圾收集(YGC)仍然采用复制存活对象到survivor空间的方式,当对象的存活年龄满足晋升条件时,将对象晋升到老年代。G1收集器通过动态改变young region的个数,来控制YGC开销,YGC过程中仍然会STW(应用停顿),并采用多线程并发复制对象,以减少GC停顿时间。
YGC是否需要扫描整个老年代是一个关键点。G1收集器通过为每个分区各自分配一个RSet(Remembered Set)来避免STW式的整堆扫描。RSet类似于一个反向指针,记录了其它region对当前region的引用情况。这样,在回收某个region时,只需要扫描它的RSet就可以找到外部引用,进而确定对象的存活状态,而这些引用就是初始标记阶段的根之一。
RSet的实现通过Card Table和HashTable来优化。Card Table将region逻辑上划分为固定大小的连续区域,称为卡片。每个卡片使用一个字节来记录是否被引用,Card Table就是这些字节的集合。当引用发生改变时,必须通知RSet,更新其中的记录。为避免冲突,G1收集器将RSet划分为多个HashTable,每个线程在各自的HashTable里修改。这样,从逻辑上来说,RSet就是这些HashTable的集合。
G1收集器的内存使用以分区(region)为单位,而对象分配则以卡片(card)为单位。因此,G1收集器中YGC不需要扫描整个老年代,只需要扫描Rset就可以知道老年代引用了哪些新生代中的对象。
G1收集器还引入了混合垃圾回收(MIXGC),当老年代占用堆空间超过初始化堆占用百分比(默认45%)时,G1就会启动一次混合垃圾回收。MIXGC不仅进行新生代垃圾收集,也回收部分后台扫描线程标记的老年代分区。MIXGC过程分为全局并发标记和拷贝存活对象两个步骤。
全局并发标记在混合回收前执行,提供标记服务。并发标记过程分为五个步骤:初始标记、根区域扫描、并发标记、重新标记和清除。其中,初始标记和重新标记阶段需要STW,而并发标记阶段与应用程序并发运行。
在清除阶段,G1收集器执行详细操作包括RSet梳理、整理堆分区和识别所有空闲分区,以制定回收计划。
当G1收集器无法在堆空间中申请新的分区时,会触发一次STW式的、单线程的Full GC。Full GC会对整堆进行标记清除和压缩,最后只保留纯粹的存活对象。参数-XX:G1ReservePercent(默认10%)可以保留空间来应对晋升模式下的异常情况,最大占用整堆50%,但更大的值并无意义。
G1收集器的缺点包括:
- 停顿时间过短可能导致每次选出的回收集只占堆内存很小一部分,收集器收集速度跟不上分配器分配速度,最终导致垃圾堆积,引发Full GC反而降低性能。
- G1收集器在垃圾收集产生的内存占用和程序运行时的额外执行负载上通常比CMS收集器更高。
- 小内存应用中,G1收集器可能由于性能原因不如CMS收集器表现良好,因此建议在大内存应用中使用G1收集器(G1收集器要求内存至少为6GB)。