垃圾收集器
快速了解
常见的垃圾回收器: 新生代收集器(高吞吐量): Serial、ParNew、Parallel Scavenge 老年代收集器(SWT停顿时间): Serial Old、CMS、Parallel Old 新生代和老年代收集器: G1、ZGC、Shenandoah
-
由于新生代和老年代垃圾收集的场景不同,所以需要不同的算法。而混合算法,一个就可以针对不同场景
每种垃圾回收器之间不是独立操作的,下图表示垃圾回收器之间有连线表示,可以协作使用:
一般的垃圾回收器搭配为:
-
Serial New(复制算法。单线程,不能利用多核) + Serial Old(标记整理。单线程) (Serial系列是单线程,GC时stop the world) JDK 5 版本之前
-
(比较古老,性能差,在项目中比较少使用)
JDK8 :
-
ParNew(复制算法。并行。 单核情况下不如Serial) + CMS(标记清除。并发)
-
适合类型:适用于需要低停顿时间(STW)的应用,如 Web 服务器、应用服务器。
-
示例应用:电商网站、在线游戏、高并发服务器。ToC项目
-
4-8G可以用ParNew+CMS
-
-
Parallel Scavenge(复制算法。并行,吞吐量优先收集器) + Parallel Old(标记整理。并行)
-
适合类型:适用于多核处理器的高吞吐量应用。
-
示例应用:科学计算、数据分析、大规模数据处理。ToB项目
-
4G以下可以用parallel
-
-
G1 (年轻代:复制 老年代:标记-整理)JDK 9 默认的收集器 要求尽可能可控 GC 停顿时间;内存占用较大的应用。
-
适合类型:适用于需要可预测停顿时间的应用,尤其是大堆内存的应用。
-
示例应用:企业级应用、中大规模 Web 服务、应用响应时间要求高的系统。
-
8G以上可以用G1
-
-
zgc:适用于需要极低停顿时间(毫秒级别)的大内存应用
-
适合类型:适用于需要极低停顿时间(毫秒级别)的大内存应用
-
示例应用:内存密集型数据库、金融交易系统、云服务。
-
几百G以上用ZGC
-
优缺点和算法区别
以下是对 ParNew + CMS、Parallel Scavenge + Parallel Old、G1 这三种垃圾收集组合的总结:
一、ParNew + CMS
-
优点:
-
低停顿时间:CMS 致力于减少垃圾收集时的停顿时间,适合对响应时间要求较高的应用场景,如互联网应用、Web 服务器等。
-
与老版本的兼容性好:在一些老的 Java 应用环境中可能更容易部署和维护。
-
-
缺点:
-
内存碎片问题:CMS 采用标记 - 清除算法,容易产生内存碎片。虽然可以通过参数在 Full GC 时进行压缩整理,但这会带来额外的停顿时间。
-
可能出现 “Concurrent Mode Failure”:当老年代空间不足时,可能会发生这种情况,导致退化为 Serial Old 收集器进行 Full GC,停顿时间会变长。
-
-
算法区别:
-
ParNew 在年轻代采用复制算法,多线程进行垃圾收集。
-
CMS 在老年代采用标记 - 清除算法,分为初始标记、并发标记、重新标记和并发清理四个阶段,其中初始标记和重新标记会暂停应用程序线程,并发标记和并发清理与应用程序线程同时运行。
-
二、Parallel Scavenge + Parallel Old
-
优点:
-
高吞吐量:以高吞吐量为主要目标,适用于对响应时间要求不高,但注重整体任务处理效率的后台批处理任务等场景。
-
算法稳定:两个收集器的算法相对简单稳定,容易理解和调优。
-
-
缺点:
-
停顿时间相对较长: 在老年代采用标记 - 整理算法,对于停顿时间的控制相对较弱,可能不适合对响应时间要求非常严格的应用。
-
-
算法区别:
-
Parallel Scavenge 在年轻代采用复制算法,通过调整参数可以控制吞吐量等指标。
-
Parallel Old 在老年代采用标记 - 整理算法,多线程进行垃圾收集。
-
三、G1
-
优点:
-
可预测的停顿时间:能够精确控制停顿时间,适用于对响应时间有较高要求的场景,同时在不牺牲大量吞吐量的情况下实现较短的停顿时间。
-
更好的内存管理:采用分区的内存布局,将堆内存划分为多个大小相等的区域,在老年代采用标记 - 整理算法,避免内存碎片问题。
-
适用于大内存应用:对于大内存(几个 GB 甚至更大)的应用表现出色。
-
-
缺点:
-
相对复杂:收集器的实现较为复杂,参数设置也相对较多,需要一定的学习和调优成本。
-
-
算法区别:
-
G1 将堆内存划分为多个区域,垃圾收集时以 Region 为单位进行操作。年轻代和老年代不再是物理隔离的,而是由一系列 Region 组成,动态的扮演年轻代和老年代角色。收集过程分为初始标记、并发标记、最终标记、筛选回收等阶段,其中初始标记和最终标记会短暂暂停应用程序线程,而并发标记和筛选回收阶段可以与应用程序线程同时运行。年轻代采用复制算法,老年代采用标记 - 整理算法。
-
总结主要区别
G1、ParNew + CMS、Parallel Scavenge + Parallel Old 这几种垃圾收集组合有以下主要区别:
一、设计目标和适用场景
-
G1(Garbage-First):
-
设计目标:同时注重低停顿时间和高吞吐量,可以在不牺牲大量吞吐量的情况下实现较短的停顿时间,适用于大内存应用和对响应时间有较高要求的场景。
-
适用场景:例如需要快速响应的交互式应用、大规模数据处理等,尤其是在堆内存较大(几个 GB 甚至更大)时表现出色。
-
-
ParNew + CMS:
-
设计目标:主要是为了降低垃圾收集的停顿时间,以满足对响应时间要求较高的应用。
-
适用场景:适合于对停顿时间比较敏感的应用,如互联网应用、Web 服务器等。但在老年代空间较大时,CMS 的并发清理阶段可能会出现 “Concurrent Mode Failure”,导致 Full GC 的停顿时间变长。
-
-
Parallel Scavenge + Parallel Old:
-
设计目标:以高吞吐量为主要目标,尽可能让应用程序的运行时间占比更高,适用于后台批处理任务等对吞吐量要求高而对停顿时间不太敏感的场景。
-
适用场景:如大数据处理、科学计算等批处理任务。
-
二、垃圾收集算法和内存布局
-
G1:
-
采用分区(Region)的内存布局,将堆内存划分为多个大小相等的区域。垃圾收集时以 Region 为单位进行操作,可以更加灵活地选择回收价值最大的区域进行回收。
-
同时,G1 结合了标记 - 整理和复制算法,在年轻代采用复制算法,在老年代采用标记 - 整理算法,避免内存碎片的产生。
-
-
ParNew + CMS:
-
ParNew 在年轻代采用复制算法。
-
CMS 在老年代采用的是标记 - 清除算法,在并发标记和并发清理阶段可以与应用程序线程同时运行,从而降低停顿时间。但标记 - 清除算法可能会产生内存碎片。
-
-
Parallel Scavenge + Parallel Old:
-
Parallel Scavenge 在年轻代采用复制算法。
-
Parallel Old 在老年代采用标记 - 整理算法,确保老年代的内存空间较为规整,减少内存碎片。
-
三、垃圾收集过程和停顿时间控制
-
G1:
-
可以精确控制停顿时间,通过设置参数
-XX:MaxGCPauseMillis
指定最大停顿时间目标,G1 会尽量在不超过这个时间内完成垃圾收集。 -
收集过程分为多个阶段,如初始标记、并发标记、最终标记、筛选回收等。其中,初始标记和最终标记阶段会短暂暂停应用程序线程,而并发标记和筛选回收阶段可以与应用程序线程同时运行。
-
-
ParNew + CMS:
-
CMS 的收集过程分为初始标记、并发标记、重新标记和并发清理四个阶段。初始标记和重新标记阶段会暂停应用程序线程,这两个阶段的停顿时间通常较短。并发标记和并发清理阶段与应用程序线程同时运行。
-
但是,如果在并发清理阶段老年代空间不足,可能会发生 “Concurrent Mode Failure”,这时会退化为 Serial Old 收集器进行 Full GC,导致较长的停顿时间。
-
-
Parallel Scavenge + Parallel Old:
-
这两个收集器都是并行收集器,在垃圾收集时会暂停所有应用程序线程。但它们会尽量在较短的时间内完成垃圾收集,以减少对应用程序的影响。
-
由于以吞吐量为主要目标,对于停顿时间的控制相对较弱。
-
四、内存碎片化处理
-
G1:
通过在老年代采用标记 - 整理算法,避免了内存碎片的产生。同时,G1 会在必要时进行混合收集,即同时回收年轻代和部分老年代的 Region,以保持内存的规整性。 -
ParNew + CMS:
CMS 采用标记 - 清除算法,容易产生内存碎片。虽然可以通过参数-XX:+UseCMSCompactAtFullCollection
在 Full GC 时进行压缩整理,但这会带来额外的停顿时间。 -
Parallel Scavenge + Parallel Old:
Parallel Old 采用标记 - 整理算法,有效地减少了内存碎片的问题。