Parallel 垃圾回收器(也称为 吞吐量优先收集器)。它是 Java 早期(特别是 JDK 8 及之前)在多核处理器上的默认垃圾回收器,其核心设计目标是最大化应用程序的吞吐量

一、Parallel 回收器的定位与设计目标

  1. 核心目标:高吞吐量 (High Throughput)

    • 吞吐量定义: 应用程序运行时间占总时间(应用程序运行时间 + 垃圾回收时间)的比例。吞吐量 = 应用运行时间 / (应用运行时间 + GC 时间) * 100%

    • 设计哲学: 为了最大化应用代码的执行效率,它愿意使用更长时间的 Stop-The-World (STW) 停顿,换取在应用运行时阶段更高的效率和更短的总运行时间。它假设应用可以容忍较长的、但次数较少的 GC 停顿。

  2. 实现方式:并行处理

    • 充分利用多核 CPU 的优势,在 STW 期间,使用多个 GC 线程并行执行垃圾回收任务(标记、复制/清除、整理),从而加快单次 GC 的速度。

    • 注意: 这里的“并行”(Parallel) 指的是 GC 线程之间的并行(多个 GC 线程同时工作),不是 GC 线程与应用程序线程的并发(Concurrent)。Parallel 回收器在进行垃圾回收时,必须暂停所有应用线程 (STW)

  3. 分代收集: 遵循分代假说,将堆划分为年轻代 (Young Generation) 和老年代 (Old Generation),并分别使用不同的并行回收器:

    • 年轻代: Parallel Scavenge (并行复制)

    • 老年代: Parallel Old (并行标记-整理) (在 JDK 6u18 之前,老年代搭配的是单线程的 Serial Old,之后 Parallel Old 成为标准搭配)

  4. 适用场景:

    • 适合后台计算密集型任务,如科学计算、批处理作业、报表生成等。

    • 应用对吞吐量要求极高,对单个 GC 停顿时间不太敏感(可以接受几百毫秒甚至秒级的停顿)。

    • 运行在多核/多 CPU 的服务器上。

二、核心组件与算法

  1. 年轻代:Parallel Scavenge (并行复制)

    • 算法: 复制算法 (Copying)

    • 堆结构: 年轻代划分为一个较大的 Eden 区和两个较小的 Survivor 区 (FromTo)。默认比例 Eden : Survivor = 8:1 (可通过 -XX:SurvivorRatio 调整)。

    • 回收过程 (STW):

      1. 触发条件:Eden 区满。

      2. STW: 暂停所有应用线程。

      3. 并行标记: 多个 GC 线程并行地从 GC Roots 出发,标记 Eden 区和当前 From Survivor 区中的存活对象。

      4. 并行复制: 多个 GC 线程并行地将标记出的存活对象复制到 To Survivor 区。

        • 新对象直接在 Eden 区分配。

        • 对象在 Survivor 区之间每熬过一次 GC,年龄增加 1。

        • 达到晋升年龄阈值 (-XX:MaxTenuringThreshold) 的对象会被晋升 (Promote) 到老年代。

        • 如果 To Survivor 区空间不足以容纳所有存活对象,或者存活对象年龄过大,会直接晋升到老年代。

      5. 清空与交换: 清空 Eden 区和刚使用完的 From Survivor 区。交换 From 和 To 的角色(下次 GC 时,当前的 To 变成新的 From)。

    • 特点: 高效、简单,没有内存碎片。STW 时间与存活对象数量成正比。

  2. 老年代:Parallel Old (并行标记-整理)

    • 算法: 标记-整理 (Mark-Compact)

    • 回收过程 (STW):

      1. 触发条件:

        • 显式调用 System.gc() (通常不建议)。

        • 老年代空间不足(例如,年轻代晋升失败,或者大对象直接进入老年代导致空间不足)。

        • 元空间 (Metaspace) / 永久代 (PermGen) 空间不足(会连带触发 Full GC)。

      2. STW: 暂停所有应用线程。

      3. 并行标记: 多个 GC 线程并行地从 GC Roots 出发,递归遍历对象图,标记老年代中所有存活对象。

      4. 并行计算整理位置: 多个 GC 线程并行地计算每个存活对象在整理后应该移动到的目标地址(通常是基于区域划分,每个线程负责一块连续区域)。

      5. 并行整理: 多个 GC 线程并行地根据上一步计算出的目标地址,将存活对象复制(移动)到新的位置。这相当于将存活对象“滑动”到堆的一端。

      6. 并行清除: 多个 GC 线程并行地更新所有指向被移动对象的引用(指针)。最后,清除掉整理后边界以外的所有空间(即死亡对象占用的空间)。

    • 特点:

      • 解决了内存碎片问题: 整理过程将存活对象紧密排列在堆的一端,腾出大块的连续空间,消除了内存碎片。

      • STW 时间较长: 整个标记-整理过程需要在 STW 下完成,且涉及全堆扫描和对象移动,对于大堆来说停顿时间可能相当可观(秒级)。

      • 吞吐量高: 并行化极大地加速了整个回收过程,相比单线程的 Serial Old 快很多。

三、核心特性与优势

  1. 高吞吐量: 这是其最主要也是最大的优势。通过并行化 GC 任务,最大限度地减少了 GC 本身所占用的时间(尽管每次停顿时间长,但频率相对较低),使得应用线程有更多的时间执行业务逻辑,特别适合需要处理大量数据、完成繁重计算任务的场景。

  2. 高效利用多核 CPU: 在 STW 期间,它能让所有可用的 CPU 核心全力投入垃圾回收工作,充分利用硬件资源加速 GC。

  3. 内存碎片控制 (Parallel Old): 老年代使用标记-整理算法,避免了像 CMS 那样的内存碎片问题,不会因为碎片导致分配失败而触发更耗时的 Full GC。

  4. 成熟稳定: 作为 JDK 8 及之前的默认回收器,经过长期发展和优化,非常成熟稳定。

四、缺点与挑战

  1. 较长的 STW 停顿时间: 这是追求高吞吐量付出的代价。无论是年轻代的 Parallel Scavenge 还是老年代的 Parallel Old,在进行回收时都必须暂停所有应用线程,且停顿时间会随着堆大小的增加而增加。这对于需要低延迟、快速响应的应用(如 Web 服务、实时交易系统)是不可接受的。

  2. 暂停时间不可预测: 停顿时间的长短主要取决于堆中存活对象的数量和堆的大小,不像 G1 或 CMS 那样有明确的停顿时间目标模型。停顿时间波动可能较大。

  3. 缺乏并发性: GC 线程与应用线程不能同时工作。在 GC 发生时,应用完全停止。

  4. 调优相对复杂 (主要针对吞吐量目标):

    • 需要平衡堆大小、各代比例与 GC 频率/停顿时间的关系。

    • 核心调优参数围绕吞吐量和停顿时间目标设定。

五、关键配置参数

  • 启用 Parallel 回收器:

    • JDK 8 及之前:默认启用。或显式指定 -XX:+UseParallelGC (启用 Parallel Scavenge + Serial Old)  -XX:+UseParallelOldGC (启用 Parallel Scavenge + Parallel Old, 推荐)。在 JDK 8 中,UseParallelGC 默认会激活 UseParallelOldGC

    • JDK 9+:不再是默认回收器 (G1 是默认),需显式指定 -XX:+UseParallelGC 或 -XX:+UseParallelOldGC

  • 设置 GC 线程数:

    • -XX:ParallelGCThreads=<n>: 设置用于年轻代和老年代并行 GC 的线程数。默认值通常等于 CPU 核心数。对于 CPU 密集型应用,设置接近核心数可最大化并行效率;对于 IO 密集型或 CPU 核心非常多的情况,可以适当减少以避免过度切换。

  • 吞吐量目标 (首要目标):

    • -XX:GCTimeRatio=<ratio>最重要的吞吐量控制参数。 设置期望的 GC 时间与应用程序时间之比。公式为 应用运行时间 = GCTimeRatio * GC 时间。默认值 99 表示 应用时间 : GC 时间 = 99 : 1,即吞吐量目标为 99% (1 - 1/(1+99) = 0.99)。增大此值(如 99 -> 199)表示允许更少的 GC 时间(更高的吞吐量),JVM 会尝试通过增大堆空间(减少 GC 频率)或更激进地回收(可能增加单次停顿时间)来实现。

  • 最大 GC 停顿时间目标 (次要目标/软目标):

    • -XX:MaxGCPauseMillis=<ms>: 设置期望的每次 GC 停顿的最大毫秒数。这是一个软目标 (Soft Goal),JVM 会尽力达成,但不保证绝对满足,且优先级低于 GCTimeRatio。默认值不设置。设置一个合理的值(如 100-500ms)可以指导 JVM 调整堆和代的大小(例如,为了减少单次停顿时间,可能会缩小年轻代,导致更频繁但更短的 Young GC)。

  • 堆大小与代大小:

    • -Xms / -Xmx: 设置堆的初始大小和最大大小。通常设置为相同值以避免堆大小动态调整的开销,这对吞吐量应用很关键。

    • -XX:NewRatio=<ratio>: 设置老年代与年轻代的比例。例如 -XX:NewRatio=3 表示 老年代:年轻代 = 3:1 (年轻代占堆的 1/4)。

    • -XX:NewSize=<size> / -XX:MaxNewSize=<size>: 直接设置年轻代的初始大小和最大大小 (优先级高于 NewRatio)。

    • -XX:SurvivorRatio=<ratio>: 设置 Eden 区与一个 Survivor 区的比例。例如 -XX:SurvivorRatio=8 表示 Eden : Survivor = 8:1 (每个 Survivor 占年轻代的 1/10)。

  • 晋升年龄控制:

    • -XX:MaxTenuringThreshold=<age>: 设置对象晋升到老年代前在年轻代经历的最大 GC 次数(年龄)。默认值 15。增大此值可以让对象在年轻代停留更久,减少晋升到老年代的数量,从而减少 Full GC 频率。但设置过大可能导致 Survivor 区溢出或对象在多次 Young GC 中反复复制。

六、调优注意事项

  1. 优先保障吞吐量 (GCTimeRatio): 这是 Parallel 回收器的核心目标。调优应首先关注 GCTimeRatio 是否达到预期。

  2. 合理设置堆大小 (-Xms=-Xmx): 足够大的堆可以减少 GC 频率。但过大的堆会导致单次 GC 停顿时间更长。找到平衡点。

  3. 监控 GC 日志: 使用 -Xlog:gc* (JDK 9+) 或 -verbose:gc + -XX:+PrintGCDetails + -XX:+PrintGCDateStamps (JDK 8) 等参数输出详细 GC 日志。分析:

    • 实际吞吐量 (应用时间 / 总时间)。

    • Young GC / Full GC 的频率和平均/最大停顿时间。

    • 各代空间占用情况、晋升情况。

  4. 理解 MaxGCPauseMillis 的副作用: 为了达到更短的停顿目标,JVM 可能会:

    • 缩小年轻代 → 增加 Young GC 频率(虽然每次短了,但总次数多了)。

    • 降低晋升年龄阈值 → 增加晋升到老年代的对象 → 增加 Full GC 频率。

    • 这些调整可能损害吞吐量 (GCTimeRatio)! 设置 MaxGCPauseMillis 需谨慎,并监控其对吞吐量的影响。

  5. 避免过早晋升: 确保 Survivor 区足够大 (SurvivorRatio),并且 MaxTenuringThreshold 设置合理,避免大量“朝生夕死”的对象过早进入老年代触发 Full GC。

七、与 CMS/G1/ZGC/Shenandoah 的对比

  • vs CMS: CMS 追求低延迟(减少 STW 时间),使用并发标记清除(有碎片问题)。Parallel 追求高吞吐量,使用并行 STW 回收(无碎片)。CMS 在 JDK 14+ 已移除。

  • vs G1: G1 也利用并行性,但核心目标是可预测的低停顿,同时兼顾高吞吐量。它采用 Region 化堆和部分回收,支持并发标记,停顿时间模型更可控。G1 是 JDK 9+ 的默认回收器,更适合需要平衡吞吐量和延迟的大堆应用。

  • vs ZGC / Shenandoah: 新一代超低延迟回收器,停顿时间目标是 亚毫秒级 (<10ms),且几乎不随堆大小增长。它们使用了染色指针、读屏障等更先进的技术实现高度并发。适用于超大堆和极致延迟要求的场景。它们也追求高吞吐量,但在极高吞吐量场景下,Parallel 可能仍有微弱的理论优势(因为并发回收器有运行时屏障开销)。

八、总结

Parallel 垃圾回收器(Parallel Scavenge + Parallel Old)是 JVM 中经典的吞吐量优先解决方案。其核心优势在于:

  • 最大化应用程序吞吐量: 通过并行化 STW 期间的垃圾回收任务,充分利用多核 CPU 资源,最小化 GC 本身占用的总时间。

  • 高效稳定: 成熟可靠,特别适合计算密集型、批处理型应用。

  • 内存整理 (Parallel Old): 避免老年代碎片问题。

其主要代价是:

  • 较长的、不可预测的 STW 停顿: 不适合延迟敏感型应用。

  • 缺乏并发处理能力。

适用场景: 当应用的核心需求是用最短的总时间完成尽可能多的工作任务(高吞吐量),并且可以容忍秒级或几百毫秒级的、偶发的暂停(如后台报表生成、科学计算、离线数据分析)时,Parallel 回收器是一个非常好的选择,尤其是在 JDK 8 环境中。在新版本 JDK (9+) 中,虽然 G1 是默认且更通用,但如果吞吐量是绝对优先指标且停顿可接受,Parallel 仍然是值得考虑的选项。对于需要极低延迟或超大堆的应用,则应考虑 G1、ZGC 或 Shenandoah。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/87988.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/87988.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/87988.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL(91)什么是分布式数据库?

分布式数据库是一种将数据存储在多个物理位置的数据库系统。这些位置可能分布在不同的服务器、数据中心甚至地理位置。分布式数据库系统允许数据的存储、处理和访问分布在多个节点上&#xff0c;以提高数据的可用性、可靠性、可扩展性和性能。 1. 分布式数据库的特点 1.1 数据…

Java事务失效(面试题)的常见场景

1. 方法非public修饰 原理&#xff1a; Spring AOP代理&#xff08;CGLIB或JDK动态代理&#xff09;默认无法拦截非public方法。 示例&#xff1a; Service public class UserService {Transactionalvoid updateUser() { // 非public方法// 事务不会生效&#xff01;} } 修…

GitHub 趋势日报 (2025年06月20日)

&#x1f4ca; 由 TrendForge 系统生成* | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 1810 data-engineer-handbook 373 n8n 295 anthropic-cookbook 291 automatisch…

qt常用控件--01

文章目录 qt常用控件--01上一篇文章的补充windowTitle属性windowIcon属性windowOpaCity属性cursor属性font属性结语 很高兴和大家见面&#xff0c;给生活加点impetus&#xff01;&#xff01;开启今天的编程之路&#xff01;&#xff01; 今天我们进一步c11中常见的新增表达 作…

C++ 中 string 类的解析及简易自我实现

目录 引言 标准库中的 string 类 功能概述 常见操作示例 自我实现简易 string 类 代码结构概述 1. String11.h 头文件 类的成员变量 迭代器相关 构造函数和析构函数 基本访问和修改方法 赋值运算符重载 内存管理和扩容 以下代码在.cpp文件中解析: 2. String11.…

计算机的性能指标(选择题0~1题无大题)

存储器的性能指标 总容量存储单元个数*存储字长 bit 例&#xff1a;MAR16位&#xff0c;MDR16位 总容量2的16次方*16bit 补充&#xff1a; n个二进制位就有2的n次方不同的状态 一般描述文件大小容量单位 2的10次方&#xff1a;K 2的20次方&#xff1a;M 2的…

React 核心原理与Fiber架构

目录 一、虚拟 DOM 二、Diffing 算法 三、Fiber 架构 四、渲染流程 1. Render 阶段&#xff08;可中断异步过程&#xff09; 2. Commit 阶段&#xff08;同步不可中断&#xff09; 五、时间切片&#xff08;Time Slicing&#xff09; 六、核心流程步骤总结 1. 状态更新…

【破局痛点,赋能未来】领码 SPARK:铸就企业业务永续进化的智慧引擎—— 深度剖析持续演进之道,引领数字化新范式

摘要 在瞬息万变的数字时代&#xff0c;企业对业务连续性、敏捷创新及高效运营的需求日益迫切。领码 SPARK 融合平台&#xff0c;秉持“持续演进”这一核心理念&#xff0c;以 iPaaS 与 aPaaS 为双擎驱动&#xff0c;深度融合元数据驱动、智能端口调度、自动化灰度切换、AI 智…

掌握C++核心特性

目标&#xff1a; 掌握C核心特性&#xff0c;为嵌入式开发打基础 好的&#xff0c;我来为你详细梳理一下 继承与多态、虚函数 相关的知识点&#xff0c;包括单继承、多继承、虚函数表机制、纯虚函数与抽象类、动态绑定。以下内容适合中等难度层次的理解&#xff0c;便于考试复…

python的高校教师资源管理系统

目录 技术栈介绍具体实现截图系统设计研究方法&#xff1a;设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理&#xff0c;难度适中&#xf…

Java Collections工具类:高效集合操作

Collections工具类概述 Collections是Java提供的集合操作工具类&#xff0c;位于java.util包中&#xff0c;包含大量静态方法&#xff0c;用于对List、Set、Map等集合进行排序、查找、替换、同步化等操作。 常用方法及代码示例 排序操作 sort(List<T> list)&#xff1a…

vue指令总结

vue指令总结 一、总述 二、代码实现&#xff08;内含大量注释&#xff09; <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>vue入门</title><!-- 使用Vue 3官方CDN --><script src"https://unpkg.c…

RUP——统一软件开发过程

RUP概述 RUP&#xff08;Rational Unified Process&#xff09;&#xff0c;统一软件开发过程&#xff0c;统一软件过程是一个面向对象且基于网络的程序开发方法论。 在RUP中采用“41”视图模型来描述软件系统的体系结构。“41”视图包括逻辑视图、实现视图、进程视图、部署视…

SpringBoot电脑商城项目--增加减少购物车商品数量

1. 持久层 1.1 规划sql语句 执行更新t_cart表记录的num值根据cid查询购物车的数据是否存在 select * from t_cart where cid#{cid} 1.2 接口和抽象方法 /*** 获取购物车中商品的数据总数* return 购物车中商品的数据总数*/Cart findByCid(Integer cid); 1.3 xml文件中sql映射…

零基础学习Redis(13) -- Java使用Redis命令

上期我们学习了如何使用Java连接到redis&#xff0c;这期我们来学习如何在java中使用redis中的一些命令 1. set/get 可以看到jedis类中提供了很多set方法 public static void test1(Jedis jedis) {jedis.flushAll();jedis.set("key1", "v1");jedis.set(&q…

解决OSS存储桶未创建导致的XML错误

前言 在Java开发中&#xff0c;集成对象存储服务&#xff08;OSS&#xff09;时&#xff0c;开发者常会遇到一个令人困惑的错误提示&#xff1a; “This XML file does not appear to have any style information associated with it. The document tree is shown below.” 此…

Spring 表达式语言(SpEL)深度解析:从基础到高级实战指南

目录 一、SpEL是什么&#xff1f;为什么需要它&#xff1f; 核心价值&#xff1a; 典型应用场景&#xff1a; 二、基础语法快速入门 1. 表达式解析基础 2. 字面量表示 3. 属性访问 三、SpEL核心特性详解 1. 集合操作 2. 方法调用 3. 运算符大全 4. 类型操作 四、Sp…

算法导论第二十四章 深度学习前沿:从序列建模到创造式AI

第二十四章 深度学习前沿&#xff1a;从序列建模到创造式AI 算法的进化正在重新定义人工智能的边界 深度学习作为机器学习领域最活跃的分支&#xff0c;正以惊人的速度推动着人工智能的发展。本章将深入探讨五大前沿方向&#xff0c;通过原理分析、代码实现和应用场景展示&…

抽象工厂设计模式

1.问题背景&#xff1a; 现在有两个产品(Product)分别是手机壳(PhoneCase)和耳机(EarPhone)&#xff0c;但是他们会来自于各个生产厂商&#xff0c;比如说Apple和Android等等 那么至少会有四个产品&#xff0c;分别是安卓手机壳&#xff0c;安卓耳机&#xff0c;苹果手机壳&a…

GESP 3级 C++ 知识点总结

根据GESP考试大纲 (2024年3月版)&#xff0c;帮大家总结一下GESP 3级 C语言的知识点&#xff1a; 核心目标&#xff1a; 掌握C程序的基本结构&#xff0c;理解并能运用基础的编程概念解决稍复杂的问题&#xff0c;重点是函数、一维数组和字符串处理。 主要知识点模块&#x…