在Java的世界里,"垃圾回收"是一个让许多开发者即侍俯首也感到神秘的术语。垃圾回收(Garbage Collection, GC)是Java虚拟机(JVM)的一个重要部分,它帮助开发者管理内存,确保程序能有效并且安全地运行。本文将介绍Java中几种常用的垃圾回收器,以及它们的工作原理和适用场景。
在Java中,对象是在堆内存上分配的,当这些对象不再被任何部分的应用所引用时,这些对象就被认为是垃圾。垃圾回收器的任务就是找到这些不再被需要的对象,并释放它们占据的内存空间,以供新对象使用。
无法控制内存是许多程序可能遇到的问题。例如,内存泄漏,这通常发生在程序不再需要的数据没有被及时清理的情况下,长此以往可能导致内存耗尽,最终程序崩溃。通过自动垃圾回收,Java试图避免这种情况。
Serial GC是最基本的垃圾回收器,适用于单核处理器的环境。它在进行垃圾回收时会暂停所有的应用线程("Stop-The-World"事件),这通常不适用于多线程的服务器环境,但可能适合于简单的命令行程序。
使用参数:
-XX:+UseSerialGC
Parallel GC又称为Throughput Collector,它使用多个线程来执行垃圾回收,因此它比Serial GC更适合多核心服务器环境。其主要关注点是提高吞吐量,缺点是在垃圾回收时仍然会有应用线程暂停。
使用参数:
-XX:+UseParallelGC
CMS GC(Concurrent Mark Sweep )的目标是减少因垃圾回收导致的停顿时间。它在回收内存的同时允许应用程序线程继续执行,适合于交互性强的应用,其中快速响应比吞吐量更重要。
使用参数:
-XX:+UseConcMarkSweepGC
G1 GC (Garbage-First)是一种服务器端垃圾回收器,它旨在填补Parallel GC和CMS GC之间的空白,提供一个低延迟的垃圾回收解决方案
。G1将堆内存分成多个不同的区域,并根据每个区域可能包含垃圾的大小来确定回收的优先顺序。
使用参数:
-XX:+UseG1GC
ZGC是一种低延迟的垃圾回收器,目前仍在积极开发中。ZGC的设计初衷是为了在大堆内存上工作,并且几乎不产生延迟。这使得它非常适合需要快速响应但是内存占用大的应用程序。
使用参数:
-XX:+UseZGC
Shenandoah GC与ZGC有类似的目标:减少停顿时间,即便是在大堆或者多核心处理器的情况下。Shenandoah通过在GC的许多阶段与应用线程并发执行来实现这一目标。
使用参数:
-XX:+UseShenandoahGC
在选择垃圾回收器时,需要考虑应用程序的需求:
JDK 8(Java Development Kit 8)中默认的垃圾回收器组合为Parallel Scavenge(用于Young Generation)加上Parallel Old(用于Old Generation)
。Parallel GC 在 JDK 5 中开始成为默认的垃圾回收器。
Parallel Scavenge收集器是一个新生代垃圾收集器,它使用复制算法
,而且是并行的多线程收集器
。它主要关注于达到一个可控制的吞吐量(Throughput)。所谓吞吐量,就是CPU用于运行用户代码的时间与CPU总消耗时间的比值,即:吞吐量 = 用户代码时间 /(用户代码时间 + 垃圾收集时间)。服务器环境中,这种收集器能够最大化的利用CPU时间,尽快地完成程序的运算任务,特别适用于多核服务器。
Parallel Old收集器是Parallel Scavenge收集器的老年代版本
,使用多线程和"标记-整理"
算法。这个收集器是在JDK 6u14版之后引入的。从JDK 9 开始默认垃圾回收器是 G1 (Garbage-First)
CMS(Concurrent Mark-Sweep)收集器是一个以获取最短回收停顿时间为目标的收集器
,使用"标记-清除
"算法,并且是并发的。但是在JDK版本的迭代中没有任何一个版本使用CMS为一个默认的垃圾回收器。
选择Parallel Scavenge和Parallel Old的原因而不用CMS,通常基于以下考虑:
吞吐量优先: 如果应用不是非常注重服务响应时间,而是更希望在单位时间内完成更多的工作,即追求较高的吞吐量,那么Parallel Scavenge加上Parallel Old垃圾收集器会是一个更合适的选择。
碎片化问题:CMS使用的"标记-清除"算法容易导致内存碎片化,当碎片化严重到一定程度,CMS需要进行一次完全停顿的垃圾收集以整理内存碎片(Full GC),这可能导致较长时间的停顿。而Parallel Old使用的"标记-整理"算法可以有效避免内存碎片化问题。
更简单稳定: 相较于CMS,Parallel Scavenge和Parallel Old通常来说维护起来比较简单,参数配置也更容易。而CMS有几百个参数需要配置调整,对于维护的成本是非常高的。
随着Java 9的发布,G1(Garbage-First)垃圾收集器成为了默认的垃圾收集器,它旨在替代CMS,提供更好的性能表现和更简单的调优选项。而在Java 11之后,还引入了ZGC和Shenandoah等实验性的低停顿时间垃圾收集器。
CMS(Concurrent Mark Sweep)和G1(Garbage-First)是Java虚拟机中的两种不同的垃圾回收器,它们各自有不同的特点和适用场景。
G1收集器是为了替代CMS收集器而设计的,提供更可预测的垃圾回收暂停时间,特别是在处理大内存容量的多处理器机器时。G1能够更好地控制停顿时间,通过将堆分割成多个区域(Region)来避免整个堆的垃圾回收,逐步地清理内存,特别适合大堆内存的应用。
随着Java虚拟机的发展,G1由于其更好的可预测性和适应性,越来越多地成为默认的垃圾收集器,尤其是在Java 9及以后的版本中。