jvm垃圾收集器

1.Serial收集器 -XX:+UseSerialGC -XX:+UseSerialOldGC

Serial 串行收集器是最基本的垃圾收集器,它是一个单线程的垃圾收集器,而且他在工作的时候必须暂停其它所有的工作线程(Stop The World)直到他收集结束。

新生代采用复制算法,老年代采用标记整理算法。

java cms垃圾器 java的垃圾收集器_后端


设计者们在后续的垃圾收集器设计中停顿时间在不断缩短。

Serial垃圾收集器简单高效,没有线程的交互开销,可以获得很高的单线程收集效率。

SerialOld收集器在1.5以及以前与Parallel Scavenge收集器搭配使用,现在可以作为CMS收集器的备用方案。2.Parallel Scavenge收集器 (-XX:+UseParallelGC -XX:+UseParallelGOldGC)

Parallel 收集器就是Serial收集器的多线程版本。默认的收集线程数和cpu核数相同,可以指定线程数但是不推荐。

Parallel收集器关注的是吞吐量(高效率的利用cpu)。cms等垃圾收集器关注的是用户线程的停顿时间(提高用户的体验)。吞吐量就是cpu运行用户业务代码的时间除以cpu总共消耗的时间。

新生代采用复制算法,老年代采用标记-整理算法。

java cms垃圾器 java的垃圾收集器_开发语言_02


JDK1.8默认的新生代和老年代收集器都是 Parallel收集器2.ParNew收集器(-XX:+UseParNewGC)

ParNew收集器和Parallel 收集器非常的相似,但是ParNew收集器可以和cms收集器一起使用。

ParNew新生代赋值算法,老年代标记整理算法。

java cms垃圾器 java的垃圾收集器_java cms垃圾器_03


他是许多运行在server模式下虚拟机的首要选择,除了Serial收集器外,只有他能和CMS收集器配合工作。3.CMS收集器(-XX:+UseConcMarkSweepGC)收集器,是一种以获取最短停顿时间为目标的收集器。非常注重用户的体验,也是HotSpot虚拟机第一款真正意义上的并发收集器,让垃圾收集线程和用户线程基本上同时工作。

CMS收集器是一种 标记-清楚算法,他的过程如下:

1.初始标记:暂停所有的其他线程STW,并记录下 gc roots直接能引用的对象,速度很快。

2.并发标记:并发标记阶段就是从GCroots直接关联的对象开始遍历整个对象图的过程,这个过程耗时较长,但是不用停顿用户线程,可以和垃圾收集线程一起并发运行。由于用户程序继续运行,所以可能会导致已经标记的对象状态发生改变。

3.重新标记:需要stw,重新标记就是为了修改并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,但是这个阶段停顿时间一般会比初识标记阶段的时间稍长,远远比并发标记阶段时间短。主要使用三色标记的增量更新算法做重新标记。

4.并发清理:开启用户线程,同时GC线程开始对未标记的区域做清理工作。这个阶段如果有新增对象会被标记为黑色不做任何处理。

5.并发重置:重置本次GC过程中的标记数据。

java cms垃圾器 java的垃圾收集器_java cms垃圾器_04


CMS是一款很好的垃圾收集器,主要优点:并发收集,停顿低。

他的缺点如下:

1.会和服务抢占资源;

2.无法处理浮动垃圾(在并发标记和并发清理阶段又产生的垃圾,这种浮动垃圾只能等到下一次gc的时候再清理了)。

3.cms使用的是标记清楚算法,会导致收集结束时会有大量的空间碎片产生, 也可以使用参数-XX:+UseCMSCompactAtFullCollection可以让jvm在执行完标记清除后再做整理

4.执行过程中不确定因素,会存在上一次垃圾回收还没执行完,然后辣鸡回收又被出发的情况,特别是在并发标记和并发清理阶段会出现,一遍回收,系统还在运行,有可能没回收玩就再次出发full gc, 也就是 concurent mode failure,这是就会STW,开始使用Serial old垃圾收集器来回收

-XX:+UseConcMarkSweepGC: 启用cms

-XX:ConcGCThreads 并发GC的线程数

XX:+UseCMSCompactAtFullCollection FullGC后做压缩整理

-XX:CMSFullGCsBeforeCompaction 多少次fullgc后进行压缩整理

-XX:CMSInitialtingOccupancyFraction: 当老年代使用达到该比例时会触发fullgc,默认是92

-XX:+UserCMSInitialtingOccupancyOnly:只使用设定好的阈值,如果不指定jvm只在第一次使用设定的阈值,下来会自动调整。

-XX:+CMSScavengeBeforeRemark: 在CMS GC前启动一次minor gc,可以减少老年代对年轻代的引用,降低cms gc的标记阶段的开销,一般cms的gc80%的耗时都在标记阶段

-XX:+CMSParallelInitialMarkEnabled:在初识标记的时候使用多线程,缩短stw

-XX:+CMSParallelRemarkEnabled:在重新标记的时候多线程,缩短stw

三色标记

在并发标记过程中,因为标记期间应用线程还在跑,对象间的引用可能发生变化,多标和漏标的情况就有可能发生。GCRoots可达性分析遍历对象过程中遇到的对象,按照是否访问过可以标记成以下三种颜色:
1.黑色:表示对象已经被垃圾收集器访问过,而且这个对象的所有引用都已经扫描过。黑色的对象代表已经扫描过,他是安全存活的,如果有其它对象 引用指向了黑色对象,无须重新扫描一遍。黑色对象不可能直接指向一个白色对象。
2.灰色:表示对象已经被垃圾收集器访问过,但是这个对象上至少存在一个引用还没有被扫描过。
3.白色:表示对象还没有被垃圾收集器访问过。在可达性分析刚刚开始的阶段所有对象都是白色,如果在分析结束的阶段还是白色,就代表对象不可达。

多标产生浮动垃圾

在并发标记过程中,当方法运行结束导致部分局部变量gcroot被销毁,这个gcroot引用的对象之前又被扫描过(被标记为非垃圾对象),那么本次GC不会回收这部分内存,这部分本应该回收但是没有回收到,被称之为浮动垃圾。浮动垃圾并不会影响垃圾回收的正确性,只要等到下次垃圾回收中进行清除。
还有,并发标记和并发清理开始后产生的新对象,通常做法就是直接全部当成黑色,本轮不会进行清除。这部分对象在这期间也会变成垃圾,这也是浮动垃圾。

漏标-读写屏障

漏标会导致被引用的对象被当成垃圾误删除,这种必须解决,有两种解决方式:增量更新和原始快照(SATB)。
增量更新:在并发阶段当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中黑色对象为根,重新扫描一次,也可以理解为:黑色对象一旦新插入了指向白色对象的引用之后,他就变成灰色对象了。
原始快照(SATB):当灰色对象要删除指向白色对象的引用关系时,就将这个要删除的引用记录下来,在并发扫描结束后,再将这些记录过的引用关系中的灰色对象为根,重新扫描一次,这样就能扫描到白色的对象,将白色对象直接标记成黑色(目的就是让这种对象在本轮gc清理中能存活下来,到下一轮gc的时候重新扫描,这个对象也有可能是浮动垃圾)。
以上两种方式虚拟机都是通过写屏障来实现的。

CMS使用的是 写屏障和增量更新
G1使用的是写屏障和SATB
ZGC使用 读屏障

记忆集和卡表,解决跨代引用的对象。