当前位置:首页 > 技术 > 正文内容

深入解析JVM主流垃圾收集器:从Serial到G1的演进与实战配置

访客 技术 2026年6月12日 1

如果说垃圾回收算法(如标记-清除、复制、标记-整理)是内存管理的理论基石,那么垃圾收集器(Garbage Collector, GC)则是这些理论在 JVM 中的具体工程实现。不同的收集器针对不同的硬件环境、堆内存大小以及应用场景(如高吞吐量或低延迟)进行了深度优化。

Serial 与 Serial Old:单线程的极致

Serial 收集器是最基础、历史最悠久的收集器。它的核心特征是"单线程",这不仅意味着它仅使用一个 CPU 核心或一条线程来执行内存回收,更关键的是,它在执行 GC 时必须挂起所有用户线程(即 Stop-The-World, STW),直到回收完成。

尽管 STW 听起来是个缺点,但在单核处理器或客户端模式(Client Mode)下,Serial 收集器由于没有多线程上下文切换的开销,反而能达到最高的内存回收效率。Serial Old 则是其在老年代的延伸,采用标记-整理算法。

# 启用 Serial 收集器(新生代与老年代均使用单线程模式)
JAVA_OPTS="-XX:+UseSerialGC"

ParNew:多核环境下的新生代搭档

ParNew 本质上是 Serial 收集器的多线程版本。除了利用多线程并行执行垃圾回收外,其核心算法和 STW 机制与 Serial 完全一致。在单核环境下,ParNew 由于线程调度开销,性能不如 Serial;但在多核服务器环境中,其并行处理能力使其成为新生代回收的首选,且通常是 CMS 收集器的默认新生代搭档。

# 强制指定使用 ParNew 作为新生代收集器
JAVA_OPTS="-XX:+UseParNewGC"

Parallel Scavenge 与 Parallel Old:吞吐量优先

与关注停顿时间的收集器不同,Parallel Scavenge(新生代)和 Parallel Old(老年代)的设计目标是最大化系统的吞吐量。吞吐量定义为 CPU 用于执行用户代码的时间占总运行时间的比例。

高吞吐量意味着 CPU 时间被高效用于业务计算,非常适合后台批处理或科学计算任务。Parallel Scavenge 引入了自适应调节策略(Ergonomics),允许 JVM 根据运行时监控数据自动调整堆大小和代际比例。

# 启用 Parallel 收集器组合,并开启自适应大小策略
JAVA_OPTS="-XX:+UseParallelGC -XX:+UseParallelOldGC -XX:+UseAdaptiveSizePolicy"

# 若需手动干预吞吐量指标,可配置以下参数:
# JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=100"  # 目标最大停顿时间
# JAVA_OPTS="$JAVA_OPTS -XX:GCTimeRatio=19"        # 目标吞吐量比率 (1 / (1 + ratio))

CMS (Concurrent Mark Sweep):低延迟的践行者

CMS 收集器专为互联网 B/S 架构设计,核心目标是获取最短的 GC 停顿时间,以提升用户体验。它基于标记-清除算法,其执行周期分为四个核心阶段:

  1. 初始标记 (STW):仅标记 GC Roots 直接关联的对象,速度极快。
  2. 并发标记:从 GC Roots 出发遍历整个对象图,与用户线程并发执行。
  3. 重新标记 (STW):修正并发标记期间因用户线程运行导致的对象引用变化,停顿时间略长于初始标记,但远短于并发标记。
  4. 并发清除:清理废弃对象,与用户线程并发执行。

CMS收集器执行流程图

CMS 的局限性:

  • CPU 资源敏感:并发阶段会占用部分 CPU 线程,导致应用程序整体吞吐量下降。
  • 内存碎片:标记-清除算法不可避免地产生空间碎片,可能提前触发 Full GC。
  • 浮动垃圾:并发清除阶段产生的新垃圾只能在下次 GC 时清理。
# 启用 CMS 收集器,并配置在 Full GC 后自动进行内存碎片整理
JAVA_OPTS="-XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection"

G1 (Garbage-First):现代化的 Region 内存模型

G1 是一款面向服务端应用的高性能收集器,旨在替代 CMS。它打破了传统物理分代的界限,将整个堆内存划分为多个大小相等的独立区域(Region)。

G1内存Region划分模型

每个 Region 都可以动态充当 Eden、Survivor 或 Old 区域。这种设计使得 G1 能够更灵活地管理内存,并建立可预测的停顿时间模型。此外,G1 专门划分了 Humongous 区域 来存储大小超过 Region 容量 50% 的巨型对象,避免了大对象在老年代中频繁复制带来的性能损耗。

G1 Region 角色动态转换

G1 的垃圾回收模式

  • Young GC:当 Eden 区域耗尽时触发,仅回收新生代 Region。存活对象被复制或晋升。
  • Mixed GC:当老年代占用率达到设定阈值(InitiatingHeapOccupancyPercent)时触发。它不仅回收所有新生代 Region,还会根据停顿时间目标,智能选择部分回收价值最高的老年代 Region 进行回收。
  • Full GC:当内存分配速度远超回收速度,导致堆空间耗尽时触发。G1 的 Full GC 会退化为单线程的 Serial Old 模式,造成极长的 STW,在生产环境中应通过调优极力避免。

G1 实战代码与参数调优

以下 Java 代码演示了如何通过分配大对象来触发 G1 的 Humongous 区域分配机制:

public class G1HumongousAllocationTest {
    // 假设 JVM 启动时配置 -XX:G1HeapRegionSize=2M
    // 当对象大小超过 1MB (2M的50%) 时,即被视为巨型对象
    private static final int ALLOCATION_SIZE = 1024 * 1024 * 2; // 2MB

    public static void main(String[] args) {
        System.out.println("Initiating Humongous object allocation...");
        
        // 分配巨型对象,G1 会直接将其放入 Humongous Region (属于老年代的一部分)
        byte[] giantPayload = new byte[ALLOCATION_SIZE];
        
        // 保持强引用,模拟业务逻辑中的大缓存或大报文
        System.out.println("Payload size: " + giantPayload.length + " bytes");
    }
}

针对 G1 收集器的核心调优参数配置参考:

JVM 参数 功能描述
-XX:+UseG1GC 启用 G1 垃圾收集器。
-XX:MaxGCPauseMillis=200 设置期望的最大 GC 停顿时间目标,G1 会据此调整回收的 Region 数量。
-XX:G1HeapRegionSize=4M 手动指定 Region 大小(1M~32M,必须是 2 的幂)。影响巨型对象的判定阈值。
-XX:InitiatingHeapOccupancyPercent=45 触发并发标记周期(进而触发 Mixed GC)的堆占用率阈值,默认 45%。
-XX:G1NewSizePercent=20 新生代可动态调整的最小百分比。
-XX:G1MaxNewSizePercent=60 新生代可动态调整的最大百分比。

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。