文章目录
- Serial回收器
- ParNew回收器
- Parallel Scavenge回收器
- Serial Old回收器
- Parallel Old回收器
- CMS(Concurrent Mark Sweeping)回收器
- G1
主要有7种垃圾回收器,如下所示:
其中有直线关联的表示,这2种垃圾回收器可以配合使用的。
Serial回收器
Serial收集器是一个单线程的垃圾回收器,所谓的单线程,就是说,只能由一个CPU或者一个线程来进行垃圾回收,同时,在进行垃圾回收的时候,会引发STW(stop the world),暂停其他线程继续运行。
主要是用于新生代的,所采用的垃圾回收算法为标记复制算法。
那么使用Serial回收器,对应的优点主要是,由于他是一个单线程的,那么就不存在线程交互的开销,可以专心做垃圾回收从而获得最高的单线程收集效率。但是他的缺点是会引起STW。
ParNew回收器
ParNew回收器是Serial回收器的多线程版本,除了使用多线程进行回收之外,其他的用法基本和Serial回收器相同,例如所使用的回收算法一样都是标记复制算法,同样会引起STW等。
并且ParNew回收器可以配合CMS回收器一起使用的,这个是它的唯一的优点。
Parallel Scavenge回收器
Parallel Scavenge回收器主要是针对新生代的,所采用的回收算法是标记复制算法。并且注重吞吐量(吞吐量 = 用户运行代码所用的时间 / (用户运行代码所用的时间 + 垃圾回收所花的时间)),通常可以通过设置参数-XX:-XX:GCTimeRatio
来控制吞吐量的大小,如果值为19,那么垃圾回收所占用的时间占总时间的5%(1 / (1 + 19))。
在jdk 1.5之前,主要是和Serial Old配合使用的,而在之后,就和Parallel Old配合使用。其中Serial Old, Parallel Old同样是针对的老年代,并且采用的都是标记整理算法进行回收垃圾的。
Serial Old回收器
Serial Old回收器是一个单线程的,并且是针对的老年代,采用的回收算法是标记整理算法。
Serial Old回收器主要用在2个地方: 在jdk 1.5之前,配合Parallel Scavenge回收器使用,其次,作为CMS回收器的一个备选方案,在并发失败之后,就会退化,使用Serial Old回收器来进行回收。
Parallel Old回收器
Parallel Old回收器是一个多线程的,并且针对的是老年代,采用的是标记整理算法回收垃圾的。并且在jdk 1.5之后,配合Parallel Scavenge回收器使用的。
CMS(Concurrent Mark Sweeping)回收器
CMS回收器针对的是老年代的一个回收器,所采用的回收算法是标记清除算法。
对应回收的流程为:
-
初始标记: 仅仅标记和GC ROOT直接关联的对象。会引发STW,也即会暂停其他所有的工作线程。
-
并发标记:标记GC ROOT能够到达的对象。它是和其他用户线程并发执行的。
-
重新标记:因为在并发标记阶段,其他的用户线程继续运行,此时就有可能导致标记记录发生了变动,所以需要重新标记这一部分变动的记录。同样会引发STW。
-
并发清理:将没有被标记的对象清除,是和其他的用户线程并发执行的,那么这时候同样可能会一些浮动垃圾(就是由用户线程运行,所产生的)。
使用CMS回收器存在的问题: -
对处理器资源非常敏感。因为在并发标记的过程中,垃圾回收线程和其他的用户线程并发执行的,那么这时候CPU的利用率并没有完全利用起来(垃圾回收线程的数目 = CPU数量 * 1/4),也即是说,如果有4个CPU,那么就有1个CPU用来进行垃圾回收的。
-
无法处理“浮动垃圾”,有可能导致并发失败而导致一次Full GC。
所谓的浮动垃圾,就是说在并发清理的过程中,其他的用户线程继续运行,这时候就会产生一些垃圾对象,由于这部分垃圾对象是在标记过程之后才产生的,所以CMS回收器并不会在这次的GC操作中回收,而需要等到下一次GC操作才会将其回收。
在进行并发清理的这个过程中,其他的用户线程继续运行。因此需要预留一定的内存空间给这些用户线程使用,对应的策略就是通过设置参数
-XX:InitatingOccupancyPercent
,一旦超过了这个值,就会执行一次垃圾回收,避免发生Full GC。
当预留的内存空间依然没有满足用户程序的需要,就会发生并发失败,此时就会使用CMS的备选方案,退化使用Serial Old回收器来进行回收。 -
采用的标记清除算法,会产生大量的内存碎片,最后导致由于没有连续的内存空间,分配给对象,而导致一次Full GC。所以需要通过设置参数
-XX:CMSFullGCsBeforeCompaction
,表示在进行多少次CMS回收后,进行一次内存压缩。(默认值为0,表示每次FullGC都进行碎片整理)
G1
G1同样拥有低延迟和吞吐量,并且拥有超大的内存,而且将内存分为若干个大小相同的Regin.
在整体上面使用的是标记整理算法,而2个Region之间使用的标记复制算法。
G1回收器的对应流程:
- 初始标记: 标记和GC ROOT直接关联的对象。会引发STW
- 并发标记:标记存活的对象。和其他的用户线程并发执行。
- 最终标记:由于在并发标记的这个过程中,其他的用户线程并发执行,所以会导致标记记录发生变动,因此需要重新标记这部分变动的记录。同样会引起STW。
- 筛选回收:会将没有标记的对象中,筛选占用内存最大的对象进行回收。
对应的流程为:
但是在最终标记这个阶段,它是通过写屏障 和一个对象来实现的,从而避免漏标等情况,例如下面的例子:
但是由于并发清理和其他用户线程是并发执行的,所以这回收的过程中,如果用户线程将B中的某一个属性的引用,指向了D对象,如下所示:
所以上面的D本不应该被回收,但是被回收了。所以就有了重新标记,需要加入写屏障,在某一个对象的引用发生变动的时候,就会加入一个写屏障,同时将这个对象加入到一个队列中,将这个对象标记为灰色,然后让另一个线程来扫描这个对象,发现这个对象是灰色的,就将其标记为黑色。如下所示:
参考: https://www.cnblogs.com/Chary/p/14428356.html