垃圾收集器ParNew&CMS与底层三色标记算法详解

本文详细介绍了Java垃圾收集器的工作原理,包括Serial、Parallel Scavenge、Parallel Old、ParNew和CMS收集器,强调了它们在年轻代和老年代使用的不同算法。此外,还详细阐述了CMS收集器的并发标记、浮动垃圾等问题,以及三色标记算法在解决并发标记阶段的多标和漏标问题上的应用。最后提到了卡表和记忆集在跨代引用中的作用,为后续探讨G1和ZGC垃圾收集器奠定了基础。
摘要由CSDN通过智能技术生成

系列文章目录

垃圾回收算法

分代收集理论
Jvm内存是分区的,分为年轻代和老年代.那么对于这两个区域都有各自的垃圾回收算法,这就是分代收集理论.
比如年轻代一次垃圾回收可能回收90%的对象.该区域的对象存活时间较短,比较适合复制算法.
再比如老年代,老年代中的对象存活时间很长,有可能是一直存活的,所以比较适合“标记-清除”算法和“标记-整理”算法.
注意:复制算法要比标记-清除/标记-整理算法快10倍以上

复制算法
为了提高回收效率,复制算法出现了.它把内存区域分为两块大小相同的区域,当一块区域满了之后执行复制算法.将满的那块区域的非垃圾对象标记出来,然后将标记的对象移入到另一块区域中,最后将满的那块区域的对象全部清空.
我们也能感觉到,复制算法效率很高,但缺点是内存空间只能使用一半.

标记-清除算法
算法分为“标记”和“清除”两个阶段.首先标记非垃圾对象,然后将未标记的垃圾对象清除.[当然也可以标记垃圾对象,一般选择标记非垃圾对象].这种算法比较简单,但是有两个问题:
1.空间问题:会造成大量的空间碎片
2.效率问题:需要清除的对象太多,效率不高

标记-整理算法
该算法与标记清除算法类似.标记非垃圾对象,然后将未标记的垃圾对象清除.不同的是,标记-整理算法会在清除之后做一次空间整理,这个可以有效的解决空间碎片的问题.

垃圾回收器

如果说垃圾收集算法是内存回收的理论知识,那么垃圾收集器就是垃圾收集算法的具体实现.
垃圾收集器
虽然我们对各个收集器进行比较,但并非为了挑选出一个最好的收集器。因为直到现在为止还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器,我们能做的就是根据具体应用场景选择适合自己的垃圾收集器。试想一下:如果有一种四海之内、任何场景下都适用的完美收集器存在,那么我们的Java虚拟机就不会实现那么多不同的垃圾收集器了。

Serial收集器(-XX:+UseSerialGC -XX:+UseSerialOldGC)
Serial是历史最悠久的垃圾收集器.通过单词我们可以知道,它是一个单线程的垃圾收集器.该收集器在新生代使用的是“复制算法”,老年代使用的是“标记-整理”算法.在进行full gc的时候会STW.
Serial垃圾收集器
Parallel Scavenge收集器(-XX:+UseParallelGC(年轻代),-XX:+UseParallelOldGC(老年代))
Parallel垃圾收集器实际上是Serial垃圾收集器的多线程版本.它在年轻代和老年代的垃圾回收算法一样,只是在垃圾回收的过程中是多个垃圾回收线程进行回收.默认的收集线程数跟cpu核数相同,当然也可以用参数(-XX:ParallelGCThreads)指定收集线程数,但是一般不推荐修改。

Parallel Scavenge主要注重于吞吐量[高效的利用CPU].CMS垃圾收集器则更关注于用户线程的停顿时间.吞吐量就是CPU中运行用户代码的时间与CPU总消耗时间的比值. Parallel Scavenge收集器提供了很多参数供用户找到最合适的停顿时间或最大吞吐量,如果对于收集器运作不太了解的话,可以选择把内存管理优化交给虚拟机去完成也是一个不错的选择。
新生代采用复制算法,老年代采用标记-整理算法
Parallel垃圾收集器
Parallel Old收集器是Parallel Scavenge收集器的老年代版本。使用多线程和“标记-整理”算法。在注重吞吐量以及CPU资源的场合,都可以优先考虑 Parallel Scavenge收集器和Parallel Old收集器(JDK8默认的新生代和老年代收集器)。

ParNew收集器(-XX:+UseParNewGC)
ParNew其实和Parallel收集器很相似,只是ParNew支持和CMS一起使用
新生代采用复制算法,老年代采用标记-整理算法
ParNew垃圾收集器
它是许多运行在Server模式下的虚拟机的首要选择,除了Serial收集器外,只有它能与CMS收集器(真正意义上的并发收集器,后面会介绍到)配合工作。

CMS收集器(-XX:+UseConcMarkSweepGC(old))
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它非常符合在注重用户体验的应用上使用,它是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作
从名字中的Mark Sweep这两个词可以看出,CMS收集器是一种 “标记-清除”算法实现的,它的运作过程相比于前面几种垃圾收集器来说更加复杂一些。整个过程分为四个步骤:

初始标记:执行STW,找到GC Root的直接引用,速度很快

并发标记:并发标记就是从上一步GC Root的直接引用进行深度遍历所有的可达对象.该过程很消耗时间.因此这个过程是不会STW,用户线程与垃圾回收线程并行执行.由于用户进程也在活动,那么这个过程中可能对象的状态是会变化的,所以需要下面的再次标记

再次标记:再次标记就是上一步标记对象的状态发生变化,对这些对象进行重新标记的过程,此阶段会STW

并发清除:用户线程与垃圾收集线程并发执行,清除标记为白色的对象[关于对象的颜色下面的三色标记算法中会详细的介绍,这里可以先理解为白色对象就是垃圾对象]

并发重置:将所有标记的对象重置
CMS垃圾收集器
从它的名字就可以看出它是一款优秀的垃圾收集器,主要优点:并发收集、低停顿。但是它有下面几个明显的缺点:
1.对CPU资源敏感,会与用户线程争夺CPU资源
2.会产生浮动垃圾:在并发标记和并发清除这两个阶段,可能会出现浮动垃圾
3.它在老年代使用的“标记-清除”算法可能会出现大量的空间碎片,当然通过参数-XX:+UseCMSCompactAtFullCollection可以让jvm在执行完标记清除后再做整理
4.执行过程的不确定性:会存在上一次垃圾回收还没执行完,然后垃圾回收又被触发的情况,特别是在并发标记和并发清理阶段会出现,一边回收,系统一边运行,也许没回收完就再次触发full gc,也就是"concurrent mode failure",此时会进入stop the world,用serial old垃圾收集器来回收。

cms的核心参数
-XX:+UseConcMarkSweepGC:启用cms
-XX:ConcGCThreads:并发的GC线程数
-XX:+UseCMSCompactAtFullCollection:FullGC之后做压缩整理(减少碎片)
-XX:CMSFullGCsBeforeCompaction:多少次FullGC之后压缩一次,默认是0,代表每次FullGC后都会压缩一次
-XX:CMSInitiatingOccupancyFraction: 当老年代使用达到该比例时会触发FullGC(默认是92,这是百分比)
-XX:+UseCMSInitiatingOccupancyOnly:只使用设定的回收阈值(-XX:CMSInitiatingOccupancyFraction设定的值),如果不指定,JVM仅在第一次使用设定值,后续则会自动调整
-XX:+CMSScavengeBeforeRemark:在CMS GC前启动一次minor gc,降低CMS GC标记阶段(也会对年轻代一起做标记,如果在minor gc就干掉了很多对垃圾对象,标记阶段就会减少一些标记时间)时的开销,一般CMS的GC耗时 80%都在标记阶段
-XX:+CMSParallellnitialMarkEnabled:表示在初始标记的时候多线程执行,缩短STW
-XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程执行,缩短STW;

下面将通过一个图灵学院的一个项目实例来介绍一下CMS的使用
亿级流量电商系统如

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值