写点什么

高频面试题 - 请把 Java 垃圾回收器说清楚

用户头像
云流
关注
发布于: 刚刚

今天我们来说一下 Java 中的垃圾回收器,之前的文章说了垃圾回收算法,这次要说的垃圾回收器会是更深层的较量,准备好了吗。

深入理解 Java 虚拟机一书中写到:如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。

不同的时代,出现了不同了垃圾收集器,它们被不断的应用在各个版本的 Java 虚拟机中。

首先来画一张图,将具体的几个垃圾收集器展示出来。



​上图就是我们要说的一共七种收集器,图中一共分为两大部分,上半部分(Serial、ParNew、Parallel Scavenge)分属于新生代收集器,下半部分(CMS、Serial Old、ParNew Old)分属于老年代收集器,而 G1 算是一个特殊的收集器,因为其不分新生代和老年代。

收集器的迭代

JDK1.3.1 之前,Serial 收集器是唯一的新生代收集器,可以说除此之外,毫无选择。

JDK1.3.1 之后,就出现了 Parallel、CMS、G1 等等的收集器。

从 JDK1.7 Update14 之后,其虚拟机中的收集器正式更换为 G1 收集器。

几个非常重要的概念

Stop The World(垃圾收集停顿机制): 当垃圾收集器在进行垃圾收集时,必须要暂停其他的所有线程,这个暂停状态将会持续到本次垃圾收集任务结束;这个过程就是 Stop The World,可以说这就是一个垃圾收集停顿机制,也是所有垃圾收集器都会有的机制,毕竟每次收集时就停顿线程,给系统会造成一定程度的延迟。

虽然没办法解决必须停顿所有线程的问题,但是经过多年的努力,多个版本垃圾收集器的更新换代,这个停顿过程也越来越短。

Throughput(吞吐量): 运行用户代码时间 / (运行用户代码时间 + 垃圾收集停顿时间),吞吐量越大,代表着收集器性能越好。

收集器中的并发和并行

(1)并发,垃圾收集任务与工作线程并发执行,但这并不代表就不会存在停顿时间,只是会大幅度减少停顿时间。

(2)并行,在收集过程中,并行执行多个收集任务,以此来减少 Stop The World 带来的停顿时间,从而提高垃圾收集的性能。

Minor GC 和 Full GC

Minor GC:新生代 GC,在新生代内存中的垃圾收集工作,具有执行频繁、回收速度快等特点。

Full GC:老年代 GC,在老年代内存中的垃圾收集工作,老年代 GC 还被称作 Major GC,在执行时,可能会执行一次 Minor GC,但是这个 Minor GC 不一定会执行;当然了,Full GC 的执行速度要比 Minor GC 的执行速度要慢数倍之多。

Serial 收集器

收集区域:新生代

使用算法:复制算法

是否支持并行:不支持,单线程收集器。

是否支持并发:不支持

号称年龄最大、最基本的收集器,作为单线程收集器,简单高效是它与其他单线程收集器之间的优势;也是因为单线程的缘故,没了线程之间的交互开销,在一定程度上,比如轻量应用级系统,就造就了其简单高效的应用模式。

这里也说一下其进行垃圾收集时的大概过程:

(1)单线程执行 GC,并且暂停所有的工作线程。

(2)采用复制算法进行收集。

(3)收集完成后,则将工作线程开启。这里还可能会继续进行 Full GC。

ParNew

收集区域:新生代

使用算法:复制算法

是否支持并行:支持,多线程收集器。

是否支持并发:不支持

ParNew 收集器可以说成是 Serial 收集器的多线程版本,除了是并行处理收集工作之外,其余的特征都与 Serial 收集器相同。

在单 CPU 的环境中,一定还是 Serial 收集器是最优选,因为多了线程交互,所以在多 CPU 的服务器环境下,ParNew 收集器的性能还是优于 Serial 收集器的。

ParNew 的工作过程大概是以下这样:

(1)多线程执行 GC,并且暂停所有的工作线程。

(2)采用复制算法进行收集。

(3)收集完成后,则将工作线程开启。这里还可能会继续进行 Full GC。

Parallel Scavenge

收集区域:新生代

使用算法:复制算法

是否支持并行:支持,多线程收集器。

是否支持并发:不支持

Parallel Scavenge 收集器这个收集器与其他收集器不同的地方,就在于其目的是为了控制吞吐量,其他收集器则是为了尽可能的提高吞吐量,也就是降低、缩短收集工作进行时的停顿时间。

Parallel Scavenge 收集器为了控制吞吐量,特定的提供了两个参数来实现吞吐量。

-XX:MaxGCPauseMillis(最大垃圾收集停顿时间):设置一个毫秒值,收集器会尽可能的保证内存的回收时间不超过这个值,并不会使收集速度变快。

-XX:GCTimeRatio(吞吐量大小):0-100 的整数,这个值就代表着垃圾收集时间在整个收集过程时间的比例。

Parallel Scavenge 收集器也被称为吞吐量收集器,还可以通过-XX:SurvivorRatio 参数设置 Eden 区和 Survivor 区的比例。

Serial Old

收集区域:老年代

使用算法:标记-整理算法

是否支持并行:不支持,单线程收集器。

是否支持并发:不支持

与 Serial 收集器略有不同,但是两者的收集工作过程没什么差异。

Parallel Old

收集区域:老年代

使用算法:标记-整理算法

是否支持并行:支持,多线程收集器。

是否支持并发:不支持

Parallel Old 从 JDK1.6 中开始提供使用,在对吞吐量要求高的情况,或者是 CPU 资源敏感的情况下,还是比较推荐考虑此收集器的。

CMS

收集区域:老年代

使用算法:标记清楚算法

是否支持并行:支持,多线程收集器。

是否支持并发:支持

CMS,全称 Concurrent Mark Sweep,旨在获取最短回收停顿时间为目标的收集器,CMS 相对比较经典,为了实现它的目标,它使用了四步来实现收集过程。

(1)初始标记(2)并发标记(3)重新标记(4)并发清除

这样就能消除 Stop The World 了吗?那是不可能的,在初始标记、并发标记时依然会出现 Stop The World。

具体的这四步主要去干了点什么,咱们回头在另一篇文章里再说。

这里还需要注意一点,那就是 CMS 是使用的标记-清楚算法,那就注定会产生大量的内存碎片,这个在面试官嘴里会常问哦。

G1

收集区域:全部

使用算法:复制算法

是否支持并行:支持,多线程收集器。

是否支持并发:支持

G1 其实是可以单独拿出一篇文章来写一下的,之后会做个详细解释,今天我们就只来看一下 G1 的几个特点。

1.并行、并发共存,在多 CPU 多核的资源下,能更有效的缩短 Stop The World 停顿的时间。

2.虽然是只用一个收集器就将所有的内存进行清理,但是依然会进行分代收集,只不过是采用了不同的方式去处理。

3.因为是管理着全部内存,所以,在空间维度上,G1 将内存分为多个 Region 空间,以此来解决用复制算法来收集的情况。

4.G1 还有一个优势就是,能可预测停顿时间。

组合使用策略

七种垃圾收集器,除了 G1 将新生代和老年代全部负责之外,其余的六种如何来搭配组合呢?

从名称上来,Serial 和 Serial Old 是可以组合的,Parallel Scavenge 和 Parallel Old 是可以组合的。

那么从现实的角度出发,Serial 可以与 Serial Old、CMS 进行组合,因为 ParNew 等同于 Serial 的多线程版本,所以 ParNew 和 Serial 一样,都可以与 Serial Old、CMS 进行组合。

Parallel Scavenge 收集器除了能和 Parallel Old 收集器配合使用,还能和 Serial Old 收集器进行组合。

来,上图,更清楚一些,​


​​

到这里,七种收集器就全部说完了,只有了解了本质后,我们也就可以逐渐进行调优的知识储备了,基础最重要,大家珍重。

作者:Ijiran

链接:https://juejin.cn/post/6994003666449629192

来源:掘金

用户头像

云流

关注

还未添加个人签名 2020.09.02 加入

还未添加个人简介

评论

发布
暂无评论
高频面试题-请把Java垃圾回收器说清楚