JVM垃圾回收器的种类及区别:
图中展示了
7
种作用于不同分代的收集器,如果两个收集器之间存在连线,则说明它们可以搭配使用。虚
拟机所处的区域则表示它是属于新生代还是老年代收集器。
新生代收集器(全部的都是复制算法):
Serial
、
ParNew
、
Parallel Scavenge
老年代收集器:
CMS
(标记
-
清理)、
Serial Old
(标记
-
整理)、
Parallel Old
(标记整理)
整堆收集器:
G1
(一个
Region
中是标记
-
清除算法,
2
个
Region
之间是复制算法)
同时,先解释几个名词:
1
,
并行(
Parallel
)
:多个垃圾收集线程并行工作,此时用户线程处于等待状态
2
,
并发(
Concurrent
)
:用户线程和垃圾收集线程同时执行
3
,
吞吐量
:运行用户代码时间/(运行用户代码时间+垃圾回收时间)
1.*
*Serial
收集器是最基本的、发展历史最悠久的收集器。
**
特点:
单线程、简单高效(与其他收集器的单线程相比),对于限定单个
CPU
的环境来说,
Serial
收集器
由于没有线程交互的开销,专心做垃圾收集自然可以获得最高的单线程手机效率。收集器进行垃圾回收
时,必须暂停其他所有的工作线程,直到它结束(
Stop The World
)。
应用场景
:适用于
Client
模式下的虚拟机。
Serial / Serial Old
收集器运行示意图
2.*
*ParNew
收集器其实就是
Serial
收集器的多线程版本。
**
除了使用多线程外其余行为均和
Serial
收集器一模一样(参数控制、收集算法、
Stop The World
、对象
分配规则、回收策略等)。
特点
:多线程、
ParNew
收集器默认开启的收集线程数与
CPU
的数量相同,在
CPU
非常多的环境中,可以
使用
-XX:ParallelGCThreads
参数来限制垃圾收集的线程数。
和
Serial
收集器一样存在
Stop The World
问题
应用场景
:
ParNew
收集器是许多运行在
Server
模式下的虚拟机中首选的新生代收集器,因为它是除了
Serial
收集器外,唯一一个能与
CMS
收集器配合工作的。
ParNew/Serial Old
组合收集器运行示意图如下:
3.*
*Parallel Scavenge
收集器与吞吐量关系密切,故也称为吞吐量优先收集器。
**
特点
:属于新生代收集器也是采用复制算法的收集器,又是并行的多线程收集器(与
ParNew
收集器类
似)。
该收集器的目标是达到一个可控制的吞吐量。还有一个值得关注的点是:
GC
自适应调节策略(与
ParNew
收集器最重要的一个区别)
GC
自适应调节策略
:
Parallel Scavenge
收集器可设置
-XX:+UseAdptiveSizePolicy
参数。当开关打开时不
需要手动指定新生代的大小(
-Xmn
)、
Eden
与
Survivor
区的比例(
-XX:SurvivorRation
)、晋升老年代
的对象年龄(
-XX:PretenureSizeThreshold
)等,虚拟机会根据系统的运行状况收集性能监控信息,动
态设置这些参数以提供最优的停顿时间和最高的吞吐量,这种调节方式称为
GC
的自适应调节策略。
Parallel Scavenge
收集器使用两个参数控制吞吐量:
XX:MaxGCPauseMillis
控制最大的垃圾收集停顿时间
XX:GCRatio
直接设置吞吐量的大小。
4.*
*Serial Old
是
Serial
收集器的老年代版本。
**
特点
:同样是单线程收集器,采用标记
-
整理算法。
应用场景
:主要也是使用在
Client
模式下的虚拟机中。也可在
Server
模式下使用。
Server
模式下主要的两大用途(在后续中详细讲解
···
):
1.
在
JDK1.5
以及以前的版本中与
Parallel Scavenge
收集器搭配使用。
2.
作为
CMS
收集器的后备方案,在并发收集
Concurent Mode Failure
时使用。
Serial / Serial Old
收集器工作过程图(
Serial
收集器图示相同):
5.*
*Parallel Old
是
Parallel Scavenge
收集器的老年代版本。
**
特点
:多线程,采用标记
-
整理算法。
应用场景
:注重高吞吐量以及
CPU
资源敏感的场合,都可以优先考虑
Parallel Scavenge+Parallel Old
收
集器。
Parallel Scavenge/Parallel Old
收集器工作过程图:
6.*
*CMS
收集器是一种以获取最短回收停顿时间为目标的收集器。
**
特点
:基于标记
-
清除算法实现。并发收集、低停顿。
应用场景
:适用于注重服务的响应速度,希望系统停顿时间最短,给用户带来更好的体验等场景下。如
web
程序、
b/s
服务。
CMS
收集器的运行过程分为下列
4
步:
初始标记
:标记
GC Roots
能直接到的对象。速度很快但是仍存在
Stop The World
问题。
并发标记
:进行
GC Roots Tracing
的过程,找出存活对象且用户线程可并发执行。
重新标记
:为了修正并发标记期间因用户程序继续运行而导致标记产生变动的那一部分对象的标记记
录。仍然存在
Stop The World
问题。
并发清除
:对标记的对象进行清除回收。
CMS
收集器的内存回收过程是与用户线程一起并发执行的。
CMS
收集器的工作过程图:
CMS
收集器的缺点:
对
CPU
资源非常敏感。
无法处理浮动垃圾,可能出现
Concurrent Model Failure
失败而导致另一次
Full GC
的产生。
因为采用标记
-
清除算法所以会存在空间碎片的问题,导致大对象无法分配空间,不得不提前触发
一次
Full GC
。
**
**
7.*
*G1
收集器一款面向服务端应用的垃圾收集器。
**
特点如下:
并行与并发:
G1
能充分利用多
CPU
、多核环境下的硬件优势,使用多个
CPU
来缩短
Stop-The-World
停顿
时间。部分收集器原本需要停顿
Java
线程来执行
GC
动作,
G1
收集器仍然可以通过并发的方式让
Java
程序
继续运行。
分代收集:
G1
能够独自管理整个
Java
堆,并且采用不同的方式去处理新创建的对象和已经存活了一段时
间、熬过多次
GC
的旧对象以获取更好的收集效果。
空间整合:
G1
运作期间不会产生空间碎片,收集后能提供规整的可用内存。
可预测的停顿:
G1
除了追求低停顿外,还能建立可预测的停顿时间模型。能让使用者明确指定在一个长
度为
M
毫秒的时间段内,消耗在垃圾收集上的时间不得超过
N
毫秒。
G1
收集器运行示意图:
**
**
关于
gc
的选择
除非应用程序有非常严格的暂停时间要求,否则请先运行应用程序并允许
VM
选择收集器(如果没有特别
要求。使用
VM
提供给的默认
GC
就好)。
如有必要,调整堆大小以提高性能。 如果性能仍然不能满足目标,请使用以下准则作为选择收集器的起
点:
如果应用程序的数据集较小(最大约
100 MB
),则选择带有选项
-XX
:
+ UseSerialGC
的串行
收集器。
如果应用程序将在单个处理器上运行,并且没有暂停时间要求,则选择带有选项
-XX
:
+
UseSerialGC
的串行收集器。
如果(
a
)峰值应用程序性能是第一要务,并且(
b
)没有暂停时间要求或可接受一秒或更长
时间的暂停,则让
VM
选择收集器或使用
-XX
:
+ UseParallelGC
选择并行收集器 。
如果响应时间比整体吞吐量更重要,并且垃圾收集暂停时间必须保持在大约一秒钟以内,则选
择具有
-XX
:
+ UseG1GC
。(值得注意的是
JDK9
中
CMS
已经被
Deprecated
,不可使用!移除
该选项)
如果使用的是
jdk8
,并且堆内存达到了
16G
,那么推荐使用
G1
收集器,来控制每次垃圾收集
的时间。
如果响应时间是高优先级,或使用的堆非常大,请使用
-XX
:
UseZGC
选择完全并发的收集
器。(值得注意的是
JDK11
开始可以启动
ZGC
,但是此时
ZGC
具有实验性质,在
JDK15
中
[202009
发布
]
才取消实验性质的标签,可以直接显示启用,但是
JDK15
默认
GC
仍然是
G1
)
这些准则仅提供选择收集器的起点,因为性能取决于堆的大小,应用程序维护的实时数据量以及可用处
理器的数量和速度。
如果推荐的收集器没有达到所需的性能,则首先尝试调整堆和新生代大小以达到所需的目标。 如果性能
仍然不足,尝试使用其他收集器
总体原则
:减少
STOP THE WORD
时间,使用并发收集器(比如
CMS+ParNew
,
G1
)来减少暂停时间,
加快响应时间,并使用并行收集器来增加多处理器硬件上的总体吞吐量。