带你看看jvm垃圾收集器

742 阅读7分钟

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版》