首页 > 编程知识 正文

下面的这些jvm垃圾回收器可以搭配cms一起使用,cms垃圾收集器采用的回收算法

时间:2023-05-03 05:22:20 阅读:285168 作者:1827

1、CMS垃圾回收的基本原理

一般老年代选用的垃圾收集器是CMS,它采用的是标记清除算法。标记清除算法就是标记出哪些是垃圾对象,然后把这些对象清理掉,标记清除有个最大的问题就是会产生内存碎片。

CMS垃圾收集器采取的是垃圾收集线程和系统工作线程尽量同时执行的模式来进行垃圾回收的,这样就能减少Stop the World的时间。

CMS进行一次垃圾回收的过程分为4个阶段:

1、初始标记

2、并发标记

3、重新标记

4、并发清理

首先,CMS进行垃圾回收时,先执行初始标记,这个阶段,会让系统工作线程全部停止,进入“Stop the World”状态。

初始标记会标记出来所有GC Roots直接引用的对象,所以速度很快,对“Stop the World”影响不大。

接着第二阶段,并发标记,这个阶段会让系统工作线程和垃圾收集线程一起执行。

在这个过程中,系统工作线程会创建新对象,同时对象也会变成垃圾对象。垃圾收集线程会对老年代所有的对象进行GC Roots追踪,对对象层层追踪,直到找到对象是否在根源上被GC Roots引用了,然后进行标记,这个过程最为耗时。但是它是和系统工作线程同时执行的,所以不会产生“Stop the World”。

第三阶段为重新标记阶段,因为在第二阶段里,一边标记存活对象和垃圾对象,一边系统不停的运行创建新对象,让老对象变成垃圾,所以在第二阶段结束后,绝对会有很多存活对象和垃圾对象未被标记。

所以在第三阶段,要让系统再次停下,进入“Stop the World”状态。然后重新标记在第二阶段里创建的一些失去引用的对象,这些失去引用的对象不多,因此标记速度很快,对“Stop the World”影响不大。

接着重新恢复系统程序运行,进入第四阶段并发清理,这个阶段,系统程序垃圾收集程序同时运行,垃圾收集程序知识对前面标记出来的垃圾对象进行清理即可。清理的阶段时很耗时的,但是他和系统程序并发执行,因此不会产生“Stop the World”,不影响系统程序运行。

以上就是CMS的基本工作原理。

2、CMS垃圾收集带来的一些问题 2.1 并发回收垃圾导致CPU资源紧张

CMS有一个最大的问题,就是在并发标记和并发清理两个最耗时的阶段,让垃圾收集线程和系统工作线程同时工作,会导致有限的CPU资源被垃圾回收线程占用了一部分。

在并发标记阶段,需要对GC Roots进行深度追踪,因为老年代存货对象比较多,因此这个过程会追踪大量的对象,耗时较高。

在并发清理阶段,又要把垃圾对象从随机的内存位置清理掉,因此也是比较耗时的。

因此这两个阶段,CMS垃圾收集线程比较耗费CPU资源,CMS默认启动的垃圾收集线程的数量为 (CPU核数+3)/4。

假如使用2核4G的机器,那么CMS就要占据宝贵的一个CPU进行垃圾回收,因此很消耗CPU资源。

2.2、Concurrent Mode Failure问题

在并发清理阶段,CMS会回收前面已经标记好的对象。但是此时系统程序在一直运行,可能随着系统运行一些对象会进入老年代,同时变成垃圾,这种垃圾称为浮动垃圾

这些浮动垃圾只能在下次GC的时候才会回收。为了保证CMS垃圾收集期间,还有一定的内存空间让一些对象进入老年代,一般会预留一部分空间。

“-XX:CMSInitiatingOccupancyFaction”参数用来设置老年代对象大小占用多少比例的时候触发CMS垃圾回收,JDK1.6默认的值是92%。

也就是说老年代空间被占用了92%了,就会自动进行CMS垃圾回收,预留8%的空间给并发清理期间新进入老年代的对象。

如果并发清理期间,系统程序要放入老年代的对象大于可用空间了会如何?

这个时候就会发生Concurrent Mode Failure,就是说并发垃圾回收失败了,一边回收垃圾,一边将对象放入老年代,导致老年代内存不足。

此时就会启用“Serial Old”垃圾回收器替代CMS,强制把系统程序“Stop the World”,重新进行长时间的GC Roots追踪,标记垃圾对象,进行回收,在这个过程不允许新对象产生,回收结束后在恢复系统线程。

因此在生产实践中,要合理优化“-XX:CMSInitiatingOccupancyFaction”参数,避免Concurrent Mode Failure问题。

3、内存碎片问题

我们知道,“标记——清除”算法会导致大量的内存碎片产生,如果内存碎片过多,就会导致后续对象进入老年代找不到可用的连续内存空间了,然后触发Full GC。

因此CMS不是完全仅仅使用“标记——清除”算法的,因为太多的内存碎片会导致更加频繁的Full GC。

CMS有一个默认打开的参数“-XX:+UseCMSCompactAtFullCollection”,意思是在Full GC之后要进行“Stop the World”,停止工作线程,进行碎片整理,就是将存货对象挪到一起,空出来大片连续空间,避免内存碎片。

还有一个参数“-XX:CMSFullGCsBrforeCompaction”,意思是执行多少次Full GC之后进行一次内存碎片整理工作,默认是0,也就是默认在每次Full GC之后都会进行一次内存整理。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。