1.引言
在介绍这些收集器各自特性之前,先明确一个观点:虽然我们会对各种垃圾收集进行比较,但并不是为了挑选一个最好的垃圾收集器,虽然一直以来,垃圾收集器的技术不断迭代更新,但是到目前为止还没有一个万能的垃圾回收器。所以我们需要根据不同应用场景选择最合适的垃圾收集器。
垃圾算法是内存回收的理论,而垃圾收集器就是内存回收的实践者。
2.Serial收集器
Serial是最基础历史最悠久的收集器,从名字来看,这款收集器是单线程垃圾收集器,单线程的意义并不是只会使用一个处理器或一条收集线程去工作。更重要的是在它进行垃圾收集时,必须暂停所有其他工作线程。也就是“Stop The World”.
对于stop the world 会给用户带来很差的的体验,官方也理解,但是也很无奈。比如说:你妈妈在给你打扫房间,肯定会让在沙发上老实待着,你妈妈一边打扫,你一边扔垃圾,这个房间什么时候才能打扫完呢?
可能会说,这个收集器出现的最早,那肯定已经被弃用了吧。从JDK1.3到现在都一直有它的一席之地。在HotSpot虚拟机客户端中,依然是默认的新生代收集器,相对于其他垃圾收集器来说,它的优点就是简单而高效。
- 内存资源受限的环境,它是所有收集器里额外内存消耗最小的
- 单核或者核数较少的处理器,由于距Serial收集器没有线程交互的开销,自然可以获得最高的单线程收集效率。
3.ParNew收集器
ParNew收集器实质上是Serial收集器的多线程并行版本,除了使用多条线程进行垃圾收集之外,其余的行为基本完全一致,也共用了很多相同的代码。
ParNew除了支持多线程并发收集之外,与其他的Serial收集器并无太大区别。但是它却是很多HosPort虚拟机服务端下的首选的新生代收集器。有一个与性能无关但很重要的原因是:除了Serial收集器之外,目前只有他能与CMS收集器配合工作。
JDK5发布时,HotSopt推出了一款具有划时代意义的收集器----CMS收集器。这是HotSopt虚拟机中第一款真正意义上支持并发的垃圾收集器,首先实现了让用户线程和收集线程同时工作。
4.Parallel Scavenge收集器
Parallel Scavenge是一款新生代垃圾收集器,基于标记-复制算法实现。
Parallel Scavenge收集器的目标是达到一个可控制的吞吐量。
- 吞吐量:处理器用于运行用户代码的时间与处理器总消耗时间的比值。
Parallel Scavenge收集器提供了两个参数
- -XX:MaxGCPauseMillis:控制最大垃圾收集停顿时间
- -XX:GCTimeRatio:直接设置吞吐量大小
- -XX:+UseAdaotiveSizePolicy:会自动根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或者最大的吞吐量。
5.Serial Old收集器
Serial Old是Serial的老年代版本,也是一个单线程收集器,使用标记-整理算法。
5.1作用
主要意义也是提供客户端模式下的HotSpot虚拟机使用。
服务器模式下:
- JDK5之前的版本与Parallel Scavenge搭配使用
- 作为CMS收集器发生失败时的预案
5.2工作过程
6.Parallel Old收集器
Parallel Old是Parallel Scavenge的老年代版本。支持多线程并发收集,基于标记-整理算法实现。这个收集器是JDK1.6才开始提供的
6.1作用
Parallel Old出现之后,可以和Parallel Scavenge组合为吞吐量优先的组合。
在注重吞吐量或者处理器资源稀缺的情况下,优先考虑PS+PO处理器组合。
6.2工作过程
7.CMS收集器
7.1简介
CMS收集器是一种以获取最短回收停顿时间为目标的收集器,基于标记-清除算法实现。
7.2运作过程
- 初始标记
- 并发标记
- 重新标记
- 并发清除
整个过程中耗时最长的并发标记和并发清除阶段中,垃圾收集器线程和用户线程都可以一起工作。总体来说,CMS收集器的内存回收过程是用户线程和收集器线程一起并发执行的。
7.3优缺点
优点:
- 并发收集
- 低停顿。
缺点:
-
cms收集器对处理器资源非常敏感
CMS默认启动的垃圾回收线程数是(处理器核心数+3)/4.
- 处理器核心数4个或以上,并发会收拾垃圾收集线程只占用不到25%的处理器资源。还会随着处理器核心数的增加而下降。
- 处理器核心数不足4个,本来处理器负载就很高,还需要分出来一半运算能力执行垃圾收集线程。
-
无法处理浮动垃圾
CMS的并发标记和并发清理阶段,用户线程同样在运行,同时就会继续产生垃圾。这一部分垃圾是出现在标记之后,所以当次回收无法清理掉,只能等下一次垃圾回收。这部分垃圾称之为浮动垃圾。
-
空间碎片的产生
CMS是基于标记-清除算法实现的,标记-清除算法就意味着会有大量的空间碎片产生,空间碎片过多时,会给大对象带来分配问题,老年代还有很多空闲空间,但是由于不是连续的,迫不得已提前触发了full GC。
8.Garbage First收集器
8.1简介
Garbage First简称G1。G1是一款主要面向服务端应用的垃圾收集器。从JDK9开始默认的垃圾收集器就是G1。
G1可以面向堆内存任何部分来组成回收集进行回收,衡量标准不再是属于哪个分代,而是那块内存中垃圾数量最多,回收收益最大,这就是G1收集器的Mixed GC模式。
8.2运作过程
- 初始标记:只是标记一下GC Roots能直接关联到的对象。并且修改TAMS指针得值。让下一阶段用户线程并发运行时,能正确地在可用的Region中分配对象。这个阶段需要停顿线程,但耗时很短,并且是借用Minor GC的时候同步完成的,所有G1在这个阶段并没有额外的停顿。
- 并发标记:从GC Roots开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这段耗时比较长,但可以与用户线程并发执行。当对象图扫描完成之后,还要重新处理SATB记录下的并发时有引用变动的对象。
- 最终标记:对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。
- 筛选回收:负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择多个Region构成回收集,然后把决定回收的那一部分Region的存活对象复制到空Region中,再清理掉整个旧的Region的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程 ,有多条垃圾收集器线程并发执行完成。
G1收集器除了并发标记外,其余阶段也是要完全暂停所有用户线程的,并非是纯粹的追求低延迟。官方给的定义是,在延迟可控的情况下尽可能提供吞吐量。
9.参考
本文参考《深入理解JVM虚拟机第3版》