JVM入门之历代垃圾回收器 2

电子说

1.3w人已加入

描述

CMS收集器

全称:Concurrent Mark Sweep

特点

  1. 「采用标记-清除算法实现」 2.和Parallel 系列的收集器注重点不同:
Parallel 注重吞吐量CMS注重STW的停顿时间

工作流程

JVM

1.初始标记

「CMS inital mark」

标记GC Roots直接关联的对象**「需要STW」**

2.并发标记

CMS concurrent mark

根据上一步和GC Roots直接关联的对象进行遍历整个堆里面的对象图并进行标记,由于是并发的所以并 「不需要停顿用户线程」 ,但是比较耗时因为遍历整个对象图。

3.重新标记

CMS remark

在并发标记期间由于和用户线程是并发的,所以这段期间用户线程可能更新了引用,所以需要进行一次修正(详见上一篇文章中讲到的 「增量更新」 ) 需要 「STW」 ,STW停顿时间比初始标记时间长,但是并没有并发标记运行时间长

4.并发清除

清除删掉被标记为垃圾的对象,由于采用的是标记-清除算法,所以并不需要移动存活对象因此是可以并发的。(当内存碎片严重到不足以分配对象时其实还是需要进行标记-整理算法的,这个时候就会提前触发FullGC。)

「注意」 :在并发阶段产生的**“浮动垃圾”**(并发时用户线程产生的垃圾),需要等到下一次垃圾回收才能进行清理;而且并发的时候需要预留一部分内存空间供用户线程使用,所以不能等到老年代完全用完在进行清理。JDK5的默认设置是当老年代使用了65%的空间就会触发GC。

G1 收集器

特点

思维方式的重大转变:

G1之前的收集器都是分代收集的思想,根据不同的代采用不同的GC:新生代(Minor GC),老年代(Major GC),整个JAVA堆(Full GC)。

但是GC是根据哪块内存中垃圾数量多回收效益最大来区分的,面向的是堆内存中的任意一块内存来组成回收集(Collection Set)进行回收。

实现

基于Region的堆内存布局来实现该回收过程。不再以固定大小及固定数量来划分分代区域,而是把连续的堆内存区域进行划分为各自独立大小相等的区域(Region),每一个Region都可以根据需要扮演新生代中的Enen空间,Survivor空间,或者老年代。收集器根据扮演不同角色的Region采用不同策略去处理。

Region中有一类特殊的Humongous区域,专门用来存储大对象。

G1认为一个对象的大小超过了一个Region空间的一半就认为该对象是大对象,如果超过了整个Region空间的超大对象将会被存放在连续的Humongous Region中,因此该区域一般会被作为老年代看待。

优点

「1.建立可预测的停顿时间模型」 :由于采用的是Region,因此回收单元作为Region即每次回收都是Region大小的整数倍。

G1会跟踪Region区域里面垃圾堆,计算出价值(回收所获得的空间大小以及回收所需时间的经验值),接着在后台维护一个优先级列表,根据用户设置的允许停顿时间来进行回收价值最大的Region区域。也就是“Garbage First” 的由来。

「2.内存碎片」 整体上采用的是标记-整理,但是在两个Region中实际上还是采用的复制算法,所以不会出现内存碎片问题。

缺点

「1.浪费额外内存来维护收集器工作」

跨代引用避免全堆扫描之前说过是采用 「记忆集」 的方式来解决,在G1中也一样。每个Region中都有自己的记忆集 「但是」 在G1中每个Region除了需要记录别的Region指向自己的指针,还需要标记这些指针分别在哪些卡页范围内。其实本质上说是哈希表,Key是别的Region的起始地址,Value是一个集合存储的元素是卡表的索引号。因此实现起来比原有的记忆集要复杂,而且Region的数量比之前的分代数量要多得多,所以记忆集的维护占用了更高的内存

G1至少要耗费大约相当于JAVA堆容量的10%到20%来存储维持收集器正常工作

「2.不仅用到写后屏障还用到了写前屏障」

上一小点中已经讲到维护卡表是需要进行添加写后屏障来完成更新卡表的操作的,但是G1还用到了写前屏障:由于使用的是原始快照来保证可以进行并发标记的基础,对比与增量更新来说虽然能够减少最终标记的停顿时间,但是相比于收集器,这款收集器不仅采用了写前屏障也采用了写后屏障导致最终的效率降低

工作流程

JVM

与之前不同的是 「最后一处」 ,这个步骤需要进行 「更新Region的统计数据,对所有的Region的回收价值和成本进行排序,然后根据用户设定的期望停顿时间进行决定选择哪几个Region构成回收集,然后将一部分的Region中存活对象复制到另外一个空的Region空间中,随后进行清理掉整个旧的Region空间」 。是不是复制算法(针对与Region来说),因为涉及对象移动,所以需要 「暂停用户线程」

总结

到此,如果读者之前阅读过笔者之前的关于垃圾回收器讲解的文章,其实已经对现在大多数垃圾回收器机制和实现原理了解的差不多了,读者有兴趣可以自行去看Shenandoah收集器和ZGC收集器,本文不在叙述,主要确实文章内容有点太长了哈哈。后面的文章将不在分析垃圾回收器的知识,但是还是会更新关于JVM的文章。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分