java cms g1垃圾回收_JVM入门到精通(七) CMS,G1垃圾回收器

一.CMS详解

CMS介绍

CMS是用于分代垃圾回收算法,老年代中。可使用户线程和GC线程同时执行的垃圾回收器。

可与Serial收集器和Parallel New收集器搭配使用。CMS牺牲了系统的吞吐量来追求收集速度,适合追求垃圾收集速度的服务器上。可以通过JVM启动参数:-XX:+UseConcMarkSweepGC来开启CMS。

从线程角度理解CMS执行过程

025a5b571774a374a14160b09a22951c.png

图中蓝色代表工作线程,黄色表示GC线程。

初始化标记(CMS-initial-mark) ,标记root,会导致stw;

并发标记(CMS-concurrent-mark),与用户线程同时运行;

预清理(CMS-concurrent-preclean),与用户线程同时运行;

重新标记(CMS-remark) ,会导致stw;

并发清除(CMS-concurrent-sweep),与用户线程同时运行;

调整堆大小,设置CMS在清理之后进行内存压缩,目的是清理内存中的碎片;

并发重置状态等待下次CMS的触发(CMS-concurrent-reset),与用户线程同时运行;

缺点

CMS收集器对CPU资源非常敏感,在并发阶段,它虽然不会导致用户线程停顿,但是由于占用了一部分线程,所以会导致应用程序变慢,总吞吐量降低。CMS默认启动的回收线程数是(cpu数量+3)/4。

CMS收集器无法处理浮动垃圾,可能出现“Concurrent Mode Failure”失败而导致一次Full GC。在JDK1.6中,CMS收集器当老年代使用了92%的空间后才会进行收集,所以如果CMS运行期间预留的内存无法满足程序需要,就会出现一次“Concurrent Mode Failure”。通过-XX:CMSInitiatingOccupancyFraction可以调整百分比。

该参数必须配合UseCMSInitiatingOccupancyOnly使用才有效

CMS由于是基于标记-清除算法实现的收集器,所以就可能会在收集结束的时候产生大量空间碎片。如果老年代中没有足够大的连续空间来分配当前对象,那么就会可能提前触发Full GC并进行碎片整理

二.G1详解

G1介绍

The Garbage First Garbage Collector (G1 GC) is the low-pause, server-style generational garbage collector for Java HotSpot VM. The G1 GC uses concurrent and parallel phases to achieve its target pause time and to maintain good throughput. When G1 GC determines that a garbage collection is necessary, it collects the regions with the least live data first (garbage first).

G1是一种服务端应用使用的垃圾收集器, 目标:在多核,大内存机器上,大多数情况下实现指定的GC暂停时间,同时保持较高吞吐。

G1内存模型

4fd549bcd01f1c8c65f1515b81f500b3.png

G1采用分而治之的思想,将堆内存划分为多个Region,每个大小在1M~32M.

物理不分代,逻辑分代。

Region

Region的大小只能是1M、2M、4M、8M、16M或32M,比如-Xmx16g -Xms16g,G1就会采用16G / 2048 = 8M 的Region.

垃圾回收时,是以Region为单位进行回收,通过CSet,记录哪些Region需要回收。优先回收垃圾最多的Region.

一个Region逻辑上属于某个分区。分区不固定,动态变化。有四种类型:old, survivor, eden, Humongous(大对象超过Region50%空间,可以占多个Region)

特点

1.并发收集

2.压缩空闲时间不会延长GC的暂停时间

3.更易预测的GC暂停时间;

4.适用于无需很高吞吐的场景

CSet

一组可被回收的分区的集合。

会占有不到整个堆空间的1%大小。

CardTable

在分代垃圾回收器中,用于标记老年代的某一块内存区域中的对象是否持有新生代对象的引用。

每张卡在卡表中对应一个比特位,当老年代中的某个对象持有了新生代对象的引用时,JVM就把这个对象对应的Card所在的位置标记为dirty(bit位设置为1),这样在Minor GC时就不用扫描整个老年代,而是扫描Card为Dirty对应的那些内存区域。

RSet

每个Region初始化时,会初始化一个remembered set(已记忆集合),该集合用来记录并跟踪其它Region指向该Region中对象的引用。

每个Region默认按照512Kb划分成多个Card,所以RSet需要记录的东西应该是 xx Region的 xx Card。

有了Rset可以避免对整个堆进行扫描。

赋值效率

由于RSet存在,每次给对象赋引用是,都要做些额外的操作(在GC中被称为写屏障),

新老年代比例

Y区比例:5%~60%

一般不用手工指定,也无需手工指定,因为这个G1预测停顿时间的基准。动态调整Y区大小。

GC何时触发

YGC

Edan空间不足, 多线程并行执行

FGC

Old空间不足

java 10以前是串行 单线程 Serial,之后并行 pall

如何避免G1产生FGC

1.扩内存,提CPU

2.降低MixedGC触发阈值,让MixedGC提早发生(默认45%)

MixedGC

GC过程和CMS类似,

稍有区别:G1并行筛选回收,

筛选出最需要回收的Region(不分老年代,年轻代),用复制压缩的算法,使区域连续,避免碎片产生。

老年代,年轻代都会回收。

三.并发标记算法

难点:在标记对象过程中,对象引用关系正在发生改变

三色标记

颜色

白色: 未被标记的对象。

灰色:自身被标记,成员变量未被标记。

黑色:自身被标记,成员变量也被标记。

漏标问题

并发标记过程中,某灰色对象A成员变量白色对象B。 对象A释放了对B的引用,黑色对象C在此时引用了A。则在并发标记的过程中,A可能会被回收。

解决方案:

1.incremental update

--增量更新,关注引用增加。 则把黑色对象,重新标记为灰色。 下次重新扫描属性,当某对象引用的对象较多时,重复扫描效率低。 是的CMS并发标记解决方案。

2.SATB

snapshot at the beginning - 关注引用的删除。 当A->B引用删除时,要把这个引用推到GC的堆栈,保证D还能被GC扫描到

G1使用SATB+RSet的解决方案,RSet记录其他对象,对当前对象的引用,效率高。

如果无RSet需要扫描整个堆栈,找那个对象引用了该对象。

颜色指针

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值