-
Notifications
You must be signed in to change notification settings - Fork 1
GC 收集器有哪些? CMS 收集器与 G1 收集器的特点
HotSpot 虚拟机有很多垃圾收集器,下图展示了 HotSpot 虚拟机的 7 个垃圾收集器。但我们并非要对全部的垃圾收集器进行深入了解,只需要着重了解 G1 垃圾收集器和 CMS 垃圾收集器。
这个收集器是一个 “单线程” 工作的收集器,但它的 “单线程” 的意义并不仅仅是说明它只会使用一个处理器或者一条收集线程去完成垃圾收集的工作,更重要的是强调在它进行垃圾收集时,必须要暂停其他所有的工作线程,直到它收集结束。
这是最早的一个垃圾收集器,在 jdk1.3 就已经出现。
该收集器是 HotSpot 虚拟机运行在客户端模式下的默认新生代收集器,对于单核处理器或者处理器核心数较少的环境来说,Serial 处理器由于没有线程交互的开销,专注于垃圾收集自然可以获得最高的单线程收集效率。分配给虚拟机的内存一般不会太大,垃圾收集的停顿时间完全可以控制在十几、几十毫秒内,只要不是频繁发生收集,这点停顿时间对用户来说是可以接受的。
ParNew 实际上是 Serial 收集器的多线程并行版本。除了 Serial 收集器外,目前只有它能与 CMS 收集器配合工作。
在 jdk1.5 开始,HotSpot 推出了 CMS 收集器,这个收集器实现了让垃圾收集线程与用户线程(基本上)同时工作。
CMS(Concurrent Mark Sweep) 收集器是一种以获取最短回收停顿时间为目标的收集器。它基于「标记-清除」算法实现的,整个过程分为 4 个步骤。
1.初始标记
仅仅只是标记一下 GC Roots 能直接关联到的对象,速度极快。
2.并发标记
从 GC Roots 的直接关联对象开始遍历整个对象图的过程,整个过程耗时较长但是不需要停顿用户线程,可以与垃圾收集线程一起并发运行。
3.重新标记
重新标记是为了修正并发标记期间,因为用户程序继续运作而导致标记产生变动的那一部分对象的标记记录。
4.并发清除
清理删除掉标记阶段判断已经死亡的对象。因为不需要移动存活对象,因此这个阶段也是可以与用户线程同时并发的。
HotSpot 收集器的弊端
- 对处理器资源比较敏感。因为占用了一部分线程而导致应用程序变慢,降低总吞吐量。
- 使用「标记-清除」算法实现,会产生大量的内存碎片,而碎片率过多会导致无法分配大对象内存而不得不提前触发一次 Full GC。为了解决该问题,CMS 收集器提供了一个 -XX:+UseCMS-CompactAtFullCollection 开关的参数(默认是开启,从 jdk9 开始废弃),用在 CMS 收集器不得不进行 Full GC 时开启内存碎片的合并整理过程。Full GC 的次数过多,会导致停顿时间过长。因此虚拟机开发者又提供了另一个参数 -XX:CMSFullGCsBefore-Compaction 参数(默认为 0,从 jdk9 废弃),表示 CMS 收集器在执行过若干次(由参数值决定)不整理空间的 Full GC 之后,下一次进入 Full GC 前会先进行碎片整理。默认为 0 表示每次进行 Full GC 都进行碎片整理。
G1 收集器全称 Garbage First,是一款面向服务端应用的垃圾收集器。在 jdk9 发布时,G1 成为了默认的垃圾收集器,而 CMS 则沦落为被声明不推荐使用的收集器。
如果在 jdk9 及以上的版本使用参数
-XX:UseConcMarkSweepGC
来开启 CMS 收集器的话,用户会收到一个警告,提示 CMS 未来可能会被废弃。
Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.
在 G1 收集器之前,所有的其他收集器,包括 CMS 在内,垃圾收集的目标范围要么是整个新生代(Minor GC),要么就是整个老年代(Major GC),再要么就是整个 Java 堆(Full GC),而 G1 跳出了这个禁锢,可以面向堆内存任何部分来组成回收集来进行回收,衡量标准不再是它属于哪一个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大,这就是 G1 收集器的 Mixed GC 模式。
G1 不再坚持固定大小以及固定数量的分代区域划分,而是把连续的 Java 堆划分成多个大小相等的独立区域(Region),每个区域(Region)都可以根据需要扮演 Eden 空间,Survivor 空间或者老年代空间。收集器能够对扮演不同角色的 Region 采用不同的策略去处理。
Region 中还有一类特殊的 Humongous 区域,专门用来存储大对象。
G1 认为只要超过了一个 Region 容量的一半即可判定为大对象。每个 Region 的取值大小可以通过参数
-XX: G1HeapRegionSize
设置,取值为 1M~32M,必须为 2n 如果超过了 Region 的大小,这类对象会被存在连续的 N 个 Region Humongous 中。
Copyright © 2020 https://dailypaper.cn
01.Java 基础
02.集合源码解析
03.Java 多线程
04.Java 虚拟机
05.计算机网络
06.算法&数据结构
07.数据库
08.Web 框架
09.面试题