专栏首页洁癖是一只狗G1和CMS垃圾收集器详解

G1和CMS垃圾收集器详解

CMS收集器是一种以获取最短回收停顿时间为目标的收集器。很大一部分是应用在互联网网站或者浏览器的B/S系统的服务端。

CMS是基于标记清除算法实现的,他的整个过程的步骤如下

  1. 初始化标记
  2. 并发标记
  3. 重新标记
  4. 并发清除

初始化标记是标记一下GC Roots能直接关联的对象,速度很快,并发标记就是从GC Roots中直接关联的对象开始遍历整个对象的过程,这个过程耗时比较长,但是用户线程不用停顿,重新标记是因为在并发标记阶段会有用户线程运行,会导致标记产生变动,这个阶段停顿时间比初始化阶段要长,但是远比并发标记停顿时间要短,而并发清除,清除那些被判断死亡的对象,此阶段不需要移动对象,因此不需要停顿用户线程

CMS的优点和缺点

优点并发收集,低停顿,但是他的缺点也是不可忽略的。

  1. CMS收集器对处理器资源非常敏感,因为在并发阶段他虽然不会停顿用户线程,但是会因为占用一部分线程而导致应用线程变慢,降低吞吐量,如果应用程序负载本来就很高,好要分出一部分处理能力去执行垃圾收集,就会导致应用的执行速度大幅降低
  2. 产生浮动垃圾,CMS在并发阶段和并发清除阶段由于用户线程一直在运行,会导致新的对象产生,而此时垃圾收集已经结束,而这部分对象只能在下次被回收,而且还要预留部分内存空间给用户线程使用,导致他并不能和其他垃圾收集器一样,等到老年代快满的时候采取垃圾收集,而是在CMS是在达到68%的时候就会激活垃圾收集,可以使用参数改变CMS的触发百分比,降低内存回收频率获取到更好的性能(-XX:CMSInitiatingOcc-pancyFraction).
  3. CMS是基于标记-清除算法,因此在垃圾回收结束之后,会产生大量空间碎片产生,其实还有许多的剩余空间,但是当一个大对象产生的时候,没有办法找到可以存放大对象,就会产生一次Full GC

Garbage First收集器(G1)

G1收集器是垃圾收集器技术历史上的一个里程碑,他开创了面向局部的设计思路和Region的内存布局形式,他是最为CMS收集器的替代者和继承人,而设计者希望可以设计出一款能够建立起停顿时间模型的收集器,停顿时间模型是指可以指定一定长度为M毫秒的时间段内,消耗在垃圾收集器上的时间大概率不能超过N毫秒的目标。

之前的垃圾收集器都是在新生代,老年代或者java整个堆进行垃圾收集,而G1并不是这样,他可以面向堆内存中任何部分组成回收集进行回收,衡量的标准不再是属于那个分代,而是那块内存存放的垃圾数量多,且回收的收益更大,这个就是G1收集器的Mixed GC模式

G1是基于Region的堆内存布局实现,G1不再坚持固定大小以及固定数量的分代区域划分,而是把连续Java堆划分成多个大小相等独立区域,每个Region扮演的角色可以是新生代Eden,Survivor空间,或者老年代,这样无论是新创建的对象还是已经被熬过了多次垃圾回收的对象都能获得很多的效果

且他还有一个Humongous对象,专门存储大对象,当一个对象的大小是Humongous大小的一半就认为是大对象,如果超过整个Region容量的超级大对象,会用N个连续的Humongous存放,Humongous Regions看做老年代的一部分,而Region是可以用参数设置大小的(-XX:G1HeapRegionSize设置,范围是1M-32M,且是2的幂次方).

虽然G1还保留着新生代和老年代的概念,但是他们不再是固定的了,而是一系列区域的动态集合,由于Region是单次回收的最小单位,每次回收的内存空间都是Region大小的整数倍,这样就可以避免整个java堆中全区域垃圾回收,而G1收集器去跟踪各个Region里面的垃圾收集的价值大小,价值即回收所获得空间大小以及回收所需要的时间经验值,而后台维护一个优先级队列类表,每次根据用户设置允许的手机停顿时间,优先回收价值收益最大的那些Region,使用Region划分内存空间,以及具有优先级的区域回收方式,保证了G1收集器在有限时间内尽可能获取高的收益效率。

Region如何解决对象引用

首先我们要知道一个东西就是卡表,我们知道如果老年代引用新生代的引用,是不是要把整个老年代加进GC Roots里面,当然不是这样的,为了解决这个问题引入了记忆集的数据结构,而记忆集的具体实现就是卡表

卡表是一个字节数组,且每一个元素的对应一个内存区域的特定大小的内存块,这个内存块就做卡页,卡页的内存包含着一个或多个对象,只要卡页有一个对象存在跨代指针,就标记对应卡表元素的值为1,称之为脏的,没有则标记为0,当发生Minor GC的时候我们直接在卡表中找到脏的,添加到GC Roots中扫描,就不必进行扫描整个老年代,扫描完之后就直接再标记卡表的元素为0.

而G1卡表是一种双向卡表的结构(我指向谁,谁指向我,进行记录),要比原来的卡表实现起来更加复杂,同时由于Region数量比传统收集器的分代数量明显要多很多,因此G1收集器要比传统的收集器更高的内存占用负担。

如何解决用户线程和收集线程互不干扰

增量更新和原始快照

如何解决可靠的停顿预测模型

用户可以通过参数-XX:MaxGCpauseMillis参数指定停顿时间仅仅意味着垃圾收集器发生之前的期望值,但是具体G1怎么做才能做到用户的预期呢.

G1是以衰减均值为理论基础来实现的,在垃圾收集的时候,G1收集器会收集每个Region的回收耗时,每个Region记忆卡集的脏卡的数量以及花费的成本,并分析平均值,标准偏差,置信度等统计信息,且衰减均值是最近的平均状态,Region的统计状态越新越能决定其回收的价值,然后通过这些信息预测现在开始回收的化,那些Region是最有价值的。

G1垃圾收集器的步骤如下

  1. 初始化标记 仅仅标记一下GC Roots关联的对象且修改TAMS指针的值,让下一次并发运行时候,能直接找到新分配的对象,这个阶段需要停顿线程,但耗时很短.
  2. 并发标记 从GC Roots开始对堆中对象进行可达性分析,递归整个堆里的对象图,找到回收的对象,这个阶段耗时长,但可以和用户线程并行运行.
  3. 最终标记 对用线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后少量的SATB记录
  4. 筛选回收 负责更新Region的统计信息,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来指定回收计划,可以自由选择任意个Region进行回收,然后把回收的那一部分存活的对象进行复制到空的Region,再清理掉旧的Region全部的空间。

G1优点和缺点

G1可以指定最大停顿时间,分Region的内存布局,按收益动态确定回收这些创新性设计带来的红利,也不会产生内存空间碎片.

但是G1也有许多弱项,就内存来说虽然G1和CMS都是使用卡表处理跨代指针,但是G1的卡表实现更复杂,且是每一个Region都会有一个卡表,而CMS只需要唯一一份卡表,因此就会导致G1记忆集可能会占整个堆内存的20%甚至更多的内存空间。

还有就是负载的角度上,G1和CMS虽然都是使用写后屏障进行卡表的维护工作,但是G1还要用写前屏障来跟踪并发时的指针变化情况,此时由于跟踪引用变化带来的额外负担。且G1对写屏障的复杂操作要比CMS消耗更多的运算资源,所以CMS的写屏障和写后屏障实现是直接的同步操作,而G1就不得不将其实现为类似消息队列的结构,把写前屏障和写后屏障中要做的事情放到队列里面,然后一步处理。

本文分享自微信公众号 - 洁癖是一只狗(rookie-dog),作者:洁癖汪

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-01-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JVM(HotSpot) 垃圾收集器

    java404
  • JVM:这是一份全面 & 详细的 常见垃圾收集器 汇总攻略

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    Carson.Ho
  • 性能优化-垃圾收集器以及内存分配

    前面我们讲了垃圾回收的算法,还需要有具体的实现,在jvm中,实现了多种垃圾收集 器,包括:串行垃圾收集器、并行垃圾收集器、CMS(并发)垃圾收集器、G1垃圾收集...

    cwl_java
  • JVM06-经典垃圾收集器

    前言相关概念并行和并发吞吐量(Throughput)Minor GC和Full GC新生代收集器Serial收集器ParNew收集器Parallel Scave...

    码农飞哥
  • 【JVM进阶之路】七:垃圾收集器盘点

    在前面,我们已经了解了JVM的分代收集,知道JVM垃圾收集在新生代主要采用标记-复制算法,在老年代主要采用标记-清除和标记-整理算法。接下来,我们看一看JDK默...

    三分恶
  • 探索G1垃圾回收器

    最近王子因为个人原因有些忙碌,导致文章更新比较慢,希望大家理解,之后也会持续和小伙伴们一起共同分享技术干货。

    HUC思梦
  • G1垃圾收集器详解(1)

    Garbage First(G1)是垃圾收集领域的最新成果,同时也是HotSpot在JVM上力推的垃圾收集器,并赋予取代CMS的使命。如果使用Java 8/9,...

    黑洞代码
  • 手撕 JVM 垃圾收集日志

    想要分析日志,首先你得有日志呀,对不对。凡是未雨绸蒙总是没错的。所谓有日志的意思,你要把 JVM 参数配置好,日志格式、日志存储位置等参数,当然了,除了日志相关...

    古时的风筝
  • G1垃圾收集器详解(2)

    G1对内存的使用以分区(Region)为单位,而对对象的分配则以卡片(Card)为单位。

    黑洞代码
  • 关于生产环境改用G1垃圾收集器的思考

    由于我们的业务量非常大,响应延迟要求高。目前沿用的老的ParNew+CMS已经不能支撑业务的需求。平均一台机器在1个月内有1次秒级别的stop the ...

    静儿
  • Java垃圾收集器之G1介绍(一)

    我是攻城师
  • JVM(五)垃圾回收器的前世今生

    如果垃圾回收的算法属于内存回收的方法论的话,那本文讨论的垃圾回收器就属于内存回收的具体实现。

    Java中文社群-磊哥
  • 一张图看懂JVM之垃圾回收器详解

    感谢读者的反馈,在?图中更新了新生代Eden区以及两个Survivor区的默认空间占比的分配表示,这里按照10等份区分8/10、1/10、1/10分别表示8:1...

    用户5927304
  • 垃圾回收的常见算法

    自动化的管理内存资源,垃圾回收机制必须要有一套算法来进行计算,那些是有效的对象,那些是无效的对象,对于无效的对象 就要进行回收处理。 常见的垃圾回收算法有 :引...

    Edison.Ma
  • JVM之垃圾收集器

    因为新生代和老年代采用回收算法的不同,垃圾收集器相应地也分为新生代收集器和老年代收集器。其中新生代收集器主要有Serial收集器、ParNew收集器和Paral...

    黑洞代码
  • 垃圾回收的常见算法

    自动化的管理内存资源,垃圾回收机制必须要有一套算法来进行计算,那些是有效的对象,那些是无效的对象,对于无效的对象 就要进行回收处理。 常见的垃圾回收算...

    海仔
  • JVM之垃圾回收-垃圾收集器

    如果说前面介绍的收集算法(JVM之垃圾回收-垃圾收集算法)是内存回收的抽象策略,那么垃圾收集器就是内存回收的具体实现。

    谙忆
  • JVM垃圾回收之垃圾回收器,程序员必须掌握的知识

    当用户线程在新生代要进行回收,这个时候就会进行STW(stop the world)操作,将其他线程全部暂停,由当前单线程进行回收垃圾,当回收完了之后,就会打开...

    黎明大大
  • 看完这篇,我再也不怕面试官问垃圾收集了

    说在前面:本文的篇幅较长,看本文的时候最好先去上个厕所,先准备好一杯枸杞茶,慢慢品,本文将会讲解三种垃圾收集算法:标记-清除、复制、标记-整理算法,以及各种成熟...

    用户5546570

扫码关注云+社区

领取腾讯云代金券