深入探索JVM垃圾收集器 — 经典垃圾收集器之Garbage First收集器(G1)

Garbage First收集器

Garbage First(简称G1)收集器是垃圾收集器技术发展历史上的里程碑式的成果,它开创了收集 器面向局部收集的设计思路基于Region的内存布局形式。被Oracle官方称为“全功能的垃圾收集 器”。

G1是一款主要面向服务端应用的垃圾收集器。JDK 9发布之 日,G1宣告取代Parallel Scavenge加Parallel Old组合,成为服务端模式下的默认垃圾收集器,而CMS则 沦落至被声明为不推荐使用(Deprecate)的收集器。

停顿时间模型:

停顿时间模型的意思是能够支持指定在一个长度为M毫秒的时间片段 内,消耗在垃圾收集上的时间大概率不超过N毫秒这样的目标。

G1,它可以面向堆内存任 何部分来组成回收集(Collection Set,一般简称CSet)进行回收,衡量标准不再是它属于哪个分代,而 是哪块内存中存放的垃圾数量最多,回收收益最大,这就是G1收集器的Mixed GC模式。

G1开创的基于Region的堆内存布局是它能够实现这个目标的关键。虽然G1也仍是遵循分

代收集理论设计的,但其堆内存的布局与其他收集器有⾮常明显的差异: G1不再坚持固定

⼤⼩以及固定数量的分代区域划分,⽽是把连续的Java堆划分为多个⼤⼩相等的独⽴区

域(Region),每⼀个Region都可以根据需要,扮演新⽣代的Eden空间、Survivor空间

或者⽼年代空间。收集器能够对扮演不同⻆⾊的Region采⽤不同的策略去处理,这样⽆

论是新创建的对象还是已经存活了⼀段时间、熬过多次收集的旧对象都能获取很好的收集

效果。

Region中还有⼀类特殊的Humongous区域,专⻔⽤来存储⼤对象。G1认为只要⼤⼩超

过了⼀个Region容量⼀半的对象即可判定为⼤对象。每个Region的⼤⼩可以通过参数-

XX: G1HeapRegionSize设定,取值范围为1M B~32M B,且应为2的N次幂。⽽对于那些

超过了整个Region容量的超级⼤对象, 将会被存放在N个连续的Humongous Region之

中,G1的⼤多数⾏为都把Humongous Region作为⽼年代的⼀部分来进⾏看待。

G1收集器之所以能建立可预测的停顿时间模型,是因为它将Region作 为单次回收的最小单元,即每次收集到的内存空间都是Region大小的整数倍,这样可以有计划地避免 在整个Java堆中进行全区域的垃圾收集。更具体的处理思路是让G1收集器去跟踪各个Region里面的垃 圾堆积的“价值”大小,价值即回收所获得的空间大小以及回收所需时间的经验值,然后在后台维护一 个优先级列表,每次根据用户设定允许的收集停顿时间(使用参数-XX:MaxGCPauseMillis指定,默 认值是200毫秒),优先处理回收价值收益最大的那些Region,这也就是“Garbage First”名字的由来。

G1收集器至少有(不限于)以下这些关键的细节问题需要妥善解决:

将Java堆分成多个独⽴Region后,Region⾥⾯存在的跨Region引⽤对象如何解决?使⽤

记忆集避免全堆作为GC Roots扫描,但在G1收集器上记忆集的应⽤其实要复杂很多,它

的每个Region都维护有⾃⼰的记忆集,这些记忆集会记录下别的Region指向⾃⼰的指

针,并标记这些指针分别在哪些卡⻚的范围之内。G1的记忆集在存储结构的本质上是⼀

种哈希表, Key是别的Region的起始地址,Value是⼀个集合,⾥⾯存储的元素是卡表的

索引号。这种“双向”的卡表结构(卡表是“我指向谁”,这种结构还记录了“谁指向我”)⽐原

来的卡表实现起来更复杂,同时由于Region数量⽐传统收集器的分代数量明显要多得

多,因此G1收集器要⽐其他的传统垃圾收集器有着更⾼的内存占⽤负担。根据经验,G1

⾄少要耗费⼤约相当于Java堆容量10%⾄20%的额外内存来维持收集器⼯作。

在并发标记阶段如何保证收集线程与⽤户线程互不⼲扰地运⾏?这⾥⾸先要解决的是⽤户

线程改变对象引⽤关系时,必须保证其不能打破原本的对象图结构,CMS收集器采⽤增

量更新算法实现,⽽G1收集器则是通过原始快照(SATB)算法来实现的。此外,垃圾收集

对⽤户线程的影响还体现在回收过程中新创建对象的内存分配上,程序要继续运⾏就肯定

会持续有新对象被创建,G1为每⼀个Region设计了两个名为TAMS(Top at Mark Start)

的指针,把Region中的⼀部分空间划分出来⽤于并发回收过程中的新对象分配,并发回

收时新分配的对象地址都必须要在这两个指针位置以上。G1收集器默认在这个地址以上

的对象是被隐式标记过的,即默认它们是存活的,不纳⼊回收范围。与CMS中的

“Concurrent Mode Failure”失败会导致Full GC类似,如果内存回收的速度赶不上内存分

配的速度,G1收集器也要被迫冻结⽤户线程执⾏,导致Full GC⽽产⽣⻓时间“Stop The

World”。

如果我们不去计算⽤户线程运⾏过程中的动作(如使⽤写屏障维护记忆集的操作),G1收集

器的运作过程⼤致可划分为以下四个步骤:

·初始标记(Initial Marking): 仅仅只是标记⼀下GC Roots能直接关联到的对象,并且修改

TAMS指针的值,让下⼀阶段⽤户线程并发运⾏时,能正确地在可⽤的Region中分配新对

象。这个阶段需要停顿线程,但耗时很短,⽽且是借⽤进⾏Minor GC的时候同步完成

的,所以G1收集器在这个阶段实际并没有额外的停顿。

 ·并发标记(Concurrent Marking): 从GC Root开始对堆中对象进⾏可达性分析,递归扫

描整个堆⾥的对象图,找出要回收的对象,这阶段耗时较⻓,但可与⽤户程序并发执⾏。

当对象图扫描完成以后,还要重新处理SATB记录下的在并发时有引⽤变动的对象。

·最终标记(Final Marking): 对⽤户线程做另⼀个短暂的暂停,⽤于处理并发阶段结束后仍

遗留下来的最后那少量的SATB记录。

·筛选回收(Live Data Counting and Evacuation): 负责更新Region的统计数据,对各个

Region的回收价值和成本进⾏排序,根据⽤户所期望的停顿时间来制定回收计划,可以

⾃由选择任意多个Region构成回收集,然后把决定回收的那⼀部分Region的存活对象复

制到空的Region中,再清理掉整个旧Region的全部空间。这⾥的操作涉及存活对象的移

动,是必须暂停⽤户线程,由多条收集器线程并⾏完成的

CMS,G1对比

相比CMS,G1的优点有很多,暂且不论可以指定最大停顿时间、分Region的内存布局、按收益动 态确定回收集这些创新性设计带来的红利,单从最传统的算法理论上看,G1也更有发展潜力。与CMS 的“标记-清除”算法不同,G1从整体来看是基于“标记-整理”算法实现的收集器,但从局部(两个Region 之间)上看又是基于“标记-复制”算法实现,无论如何,这两种算法都意味着G1运作期间不会产生内存 空间碎片,垃圾收集完成之后能提供规整的可用内存。这种特性有利于程序长时间运行,在程序为大 对象分配内存时不容易因无法找到连续内存空间而提前触发下一次收集。

不过,G1相对于CMS仍然不是占全⽅位、压倒性优势的,从它出现⼏年仍不能在所有应

⽤场景中代替CMS就可以得知这个结论。⽐起CMS,G1的弱项也可以列举出不少,如在

⽤户程序运⾏过程中,G1⽆论是为了垃圾收集产⽣的内存占⽤(Footprint)还是程序运⾏

时的额外执⾏负载(Overload)都要⽐CMS要⾼。

⽬前在⼩内存应⽤上CMS的表现⼤概率仍然要会优于G1,⽽在⼤内存应⽤上G1则⼤多能

发挥其优势,这个优劣势的Java堆容量平衡点通常在6GB⾄8GB之间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
JVM (Java Virtual Machine) G1 (Garbage-First) 垃圾收集器是一种用于 Java 应用程序的垃圾收集算法。它是自JDK 7u4版本后引入的一种全新的垃圾收集器G1垃圾收集器的设计目标是为了解决传统的分代垃圾收集器可能遇到的一些问题,如停顿时间长、内存碎片化等。它采用了一种基于区域的垃圾收集方式,可以将内存划分为多个大小相等的区域,每个区域可以是Eden、Survivor或Old区。 G1垃圾收集器的工作原理如下: 1. 初始标记(Initial Mark):标记所有从根对象直接可达的对象。 2. 并发标记(Concurrent Mark):在并发执行程序的同时,标记那些在初始标记阶段无法访问到的对象。 3. 最终标记(Final Mark):为并发标记阶段中发生改变的对象进行最终标记。 4. 筛选回收(Live Data Counting and Evacuation):根据各个区域的回收价值来优先回收价值低的区域。 G1垃圾收集器具有以下特点: - 并发执行:在执行垃圾收集过程时,尽可能减少应用程序的停顿时间。 - 分区回收:将整个堆划分为多个区域,可以根据需要优先回收垃圾较多的区域,从而避免全堆回收带来的长时间停顿。 - 内存整理:G1垃圾收集器会对内存进行整理,减少内存碎片化,提高内存利用率。 需要注意的是,G1垃圾收集器并不适用于所有情况。在特定的场景下,如大堆情况下的长时间运行、对延迟要求非常高的应用等,可能需要考虑其他垃圾收集器的使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值