垃圾收集器

以下内容来自《深入理解 Java 虚拟机》(第二版)——周志明

这里讨论的收集器基于 JDK 1.7 Update 14 之后的 HotSpot 虚拟机。上图展示了 7 种作用于不同分代的收集器,如果两个收集器之间存在连线,就说明它们可以搭配使用。

  1. Serial 收集器

    Serial 收集器是最基本,发展历史最悠久的收集器。他是一个单线程的收集器,但它的 “单线程” 的意义并不仅仅说明它只会使用一个 CPU 或一条收集线程去完成垃圾收集工作,更重要的是在它进行垃圾收集时,必须暂停其他所有的工作线程,直到它收集结束。Serial 收集器对于运行在 Client 模式下的虚拟机来说是一个很好的选择。

  2. ParNew 收集器

    ParNew 收集器其实就是 Serial 收集器的多线程版本,除 Serial 收集器以外,只有它能与 CMS 收集器配合工作。

  3. Parallel Scanvenge 收集器

    采用复制算法,多线程。Parallel Scanvenge 收集器的特点是它的关注点与其他收集器不同,CMS等收集器的关注点是尽可能地缩短垃圾收集时用户线程的停顿时间,而 Parallel Scanvenge 收集器的目标则是达到一个可控制的吞吐量。吞吐量 = 运行用户代码时间 / (运行用户代码时间 + 垃圾收集时间),虚拟机总共运行 100 分钟,其中垃圾收集用了 1 分钟,那么吞吐量就是 99%。

    停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效率的利用 CPU 的时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。

  4. Serial Old 收集器

    Serial Old 收集器是 Serial 收集器的老年代版本,它同样是一个单线程收集器,使用 “标记 - 整理算法” 。这个收集器的主要意义也是在于给 Client 模式下的虚拟机使用。如果在 Server 模式下,一种用途就是作为 CMS 收集器的后备预案,在并发收集发生 Concurrent Mode Failure 时使用。

  5. Parallel Old 收集器

    Parallel Old 是 Parallel Scanvenge 收集器的老年代版本,使用多线程和 “标记 - 整理算法”。出现 Parallel Old 收集器后,“吞吐量优先” 收集器终于有了比较名副其实的应用组合,在注重吞吐量以及 CPU 资源敏感的场合,都可以考虑Parallel Scanvenge 加 Parallel Old 收集器。

  6. CMS 收集器(Concurrent Mark Sweep)

    CMS 收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大的一部分 Java 应用集中在互联网站或者 B/S 系统的服务端上,这类应用尤其重视服务的响应速度,希望系统的停顿时间最短,以提升用户体验,CMD 收集器就非常符合这类应用的需求。

    CMS 基于 “标记 - 清除算法”,它的运作过程对于前面的几种收集器来说更复杂一些,整个过程分为 4 个步骤:

    • 初始标记
    • 并发标记
    • 重新标记
    • 并发清除

    其中初始标记和重新标记仍然需要 STW。初始标记仅仅标记一下 GC Roots 能直接关联到的对象,速度很快,并发标记就是进行 GC Roots Tracing 的过程,而重新标记则是为了修正并发标记期间因用户继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段一般会比初始标记长一些,但远比并发标记的时间短。

    由于整个过程中耗时最长的并发标记和并发清除过程是与用户线程一起并发执行的,所以从总体上来说,CMS 收集器的内存回收过程是与用户线程一起并发执行的。

    CMS 收集器有以下三个明显的缺点:

    • 对 CPU 资源非常敏感

      会因为占用了一部分线程(或者说 CPU 资源)而导致应用程序变慢,总吞吐量降低

    • 无法处理浮动垃圾

      在并发清理阶段由用户线程产生的新垃圾出现再标记过程之后,只能留到下一次 GC 再处理,这一部分垃圾称为浮动垃圾。也由于垃圾收集阶段用户线程还在继续,所以需要预留一部分空间提供给用户线程使用, CMS 不能像其他线程一样等老年代塞满了之后再进行回收。要是 CMS 运行期间预留的内存无法满足程序需要,就会出现一次 “Concurrent Mode Failure”

    • 可能会产生大量空间碎片

      由于是 “标记 - 清除算法” 可能会产生大量空间碎片,会给大对象的内存分配带来很大麻烦,往往出现老年代还剩很大空间,但是没有足够大的连续空间来分配当前对象,不得不提前触发 Full GC

  7. G1 收集器

    HotSpot 团队希望它能够在未来替换掉 CMS 收集器。G1 具备以下特点:

    • 并行与并发

      使用多个 CPU 来缩短 STW 的时间,部分其他收集器原本需要停顿 Java 线程执行的 GC 动作,G1 收集器仍然可以通过并发的方方式让 Java 程序继续执行

    • 分代收集

      G1 中依然有分代的概念,虽然 G1 可以独自管理整个 GC 堆,但它能够以不同的方式处理新创建的对象和已经存活了一段时间的对象、熬过多次 GC 的旧对象来获取更好的收集效果。

    • 空间整合

      G1 从整体上来看是基于 “标记 - 整理” 算法实现的收集器,从局部(两个 Region 之间)来看是基于 “复制” 算法实现的,但无论如何这两种算法都不会产生内存空间碎片,收集后能提供规整的可用内存,这种特性有利于程序长时间运行。

    • 可预测的停顿

      能够让使用者明确指定一个长度为 M 毫秒的时间片段内,消耗在垃圾收集上的时间不超过 N 毫秒。这是因为 G1 跟踪各个 Region 里面的垃圾堆积的价值大小(回收所获得的空间大小以及回收所需时间的经验值),在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的 Region (这也是 Garbage - First 名称的由来)。

    在 G1 收集器中,Region 之间的对象引用以及其他收集器中的新生代和老年代之间的对象引用,虚拟机都是使用 Remembered Set 来避免全堆扫描的。如果不计算 维护 Remembered Set 的操作,G1 收集器的运作步骤大致可划分为以下几个步骤:

    • 初始标记
    • 并发标记
    • 最终标记
    • 筛选回收

    初始标记和 CMS 一样需要停顿,筛选回收会对各个 Region 中的回收价值和成本进行排序,并根据用户期望的停顿时间来制定回收计划。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值