跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

JVM 垃圾收集器:ParNew、CMS 与三色标记算法

JVM 垃圾收集理论及三大基础算法(标记 - 复制、标记 - 清除、标记 - 整理),详细对比了新生代与老年代收集器特性,重点解析了 ParNew 与 CMS 收集器的配合机制。同时深入阐述了底层核心机制,包括三色标记算法原理、读写屏障实现以及记忆集与卡表优化方案,并结合亿级流量场景给出了 ParNew+CMS 的参数优化实战建议。

云间漫步发布于 2026/3/27更新于 2026/10/26118 浏览

一、垃圾收集算法

1. 分代收集理论
  • 核心思想:根据对象存活周期不同,将 Java 堆分为新生代和老年代,适配不同垃圾收集算法
  • 分代依据:
    • 新生代:对象存活时间短,每次 GC 大量对象(近 99%)回收,适合复制算法
    • 老年代:对象存活概率高,无额外空间担保,适合标记 - 清除 / 标记 - 整理算法
  • 性能差异:标记 - 清除 / 标记 - 整理算法比复制算法慢 10 倍以上
2. 三大基础垃圾收集算法
(1)标记 - 复制算法
  • 原理:将内存分为大小相等的两块,每次使用一块;内存耗尽时,复制存活对象到另一块,清空原块
  • 适用场景:新生代(Serial、ParNew、Parallel Scavenge 收集器)
  • 优点:效率高,无内存碎片
  • 缺点:内存利用率低(仅 50%)
(2)标记 - 清除算法
  • 原理:
    1. 标记阶段:标记存活对象(或需回收对象)
    2. 清除阶段:统一回收未标记(或已标记)对象
  • 适用场景:老年代(CMS 收集器)
  • 优点:实现简单
  • 缺点:
    1. 效率低(标记对象过多时)
    2. 产生大量不连续内存碎片
(3)标记 - 整理算法
  • 原理:标记阶段与标记 - 清除一致,后续将所有存活对象向一端移动,清理边界外内存
  • 适用场景:老年代(Serial Old、Parallel Old 收集器)
  • 优点:无内存碎片,内存利用率高
  • 缺点:增加对象移动开销,效率低于复制算法
3. 算法对比总结
算法优点缺点适用代际
标记 - 复制效率高、无碎片内存利用率低新生代
标记 - 清除实现简单、无需移动效率低、产生碎片老年代
标记 - 整理无碎片、利用率高效率低、有移动开销老年代

二、垃圾收集器

1. 收集器分类与核心特性
(1)新生代收集器
收集器线程模型算法核心特点参数配置
Serial单线程标记 - 复制简单高效、STW 时间长
-XX:+UseSerialGC
ParNew多线程标记 - 复制可与 CMS 配合、多线程并发-XX:+UseParNewGC
Parallel Scavenge多线程标记 - 复制注重吞吐量、自适应调节-XX:+UseParallelGC
(2)老年代收集器
收集器线程模型算法核心特点参数配置
Serial Old单线程标记 - 整理单线程、作为 CMS 后备-XX:+UseSerialOldGC
Parallel Old多线程标记 - 整理注重吞吐量、Parallel 配套-XX:+UseParallelOldGC
CMS并发标记 - 清除低停顿、并发收集-XX:+UseConcMarkSweepGC
2. 重点收集器详解
(1)Serial 收集器(串行收集器)
  • 线程模型:单线程(GC 线程 + STW 所有用户线程)
  • 算法实现:新生代复制算法,老年代标记 - 整理算法
  • 优点:无线程交互开销,单线程效率高
  • 缺点:STW 时间长,不适用于多核服务器
  • 适用场景:客户端应用、小型程序
(2)Parallel 系列收集器(吞吐量优先)
  • Parallel Scavenge(新生代)
    • 多线程收集,默认线程数 = CPU 核数(可通过 -XX:ParallelGCThreads 调整)
    • 核心目标:吞吐量(用户代码运行时间 / CPU 总时间)
    • 支持自适应调节(自动优化停顿时间 / 吞吐量)
  • Parallel Old(老年代)
    • 多线程 + 标记 - 整理算法
    • JDK8 默认老年代收集器
    • 适用场景:注重吞吐量、CPU 资源敏感的服务
(3)ParNew 收集器(CMS 配套)
  • 本质是 Parallel Scavenge 的多线程版本,唯一能与 CMS 配合的新生代收集器
  • 支持多线程并发收集,STW 时间比 Serial 短
  • 适用场景:Server 模式、需与 CMS 配合的服务
(4)CMS 收集器(低停顿优先)
  • 核心目标:最短回收停顿时间(用户体验优先)
  • 线程模型:并发收集(垃圾收集线程与用户线程同时运行)
  • 算法实现:标记 - 清除算法

文章配图

  1. 初始标记:STW,记录 GC Roots 直接引用对象(速度快)
  2. 并发标记:无 STW,遍历对象图(耗时久,与用户线程并发)
  3. 重新标记:STW,修正并发标记的漏标(比初始标记久,远短于并发标记)
  4. 并发清理:无 STW,清理未标记对象(新对象标记为黑色)
  5. 并发重置:重置标记数据
  • 优点:并发收集、低停顿
  • 缺点:
    1. CPU 资源敏感(与服务抢资源)
    2. 产生浮动垃圾(需下次 GC 清理)
    3. 内存碎片(可通过参数优化)
    4. 可能出现 Concurrent Mode Failure(触发 Serial Old 回收)
  • 核心参数:
    • -XX:ConcGCThreads:并发 GC 线程数
    • -XX:+UseCMSCompactAtFullCollection:FullGC 后整理碎片
    • -XX:CMSInitiatingOccupancyFraction:老年代使用率阈值(默认 92%)
    • -XX:+CMSScavengeBeforeRemark:Remark 前触发 Minor GC
3. 收集器选择原则
  • 无万能收集器,需根据场景选择:
    • 客户端 / 小型应用:Serial + Serial Old
    • 吞吐量优先:Parallel Scavenge + Parallel Old
    • 低停顿 / 用户体验优先:ParNew + CMS
    • 大内存(>4G)+ 低停顿:G1/ZGC/Shenandoah(扩展)

三、底层核心机制

1. 三色标记算法(并发标记核心)
(1)核心概念
  • 标记规则:按对象访问状态分为三种颜色:
    • 黑色:已访问,且所有引用已扫描(安全存活,不指向白色对象)
    • 灰色:已访问,但存在未扫描引用
    • 白色:未访问(分析结束后仍为白色则需回收)

核心问题:并发标记时,用户线程修改对象引用导致 "多标" 或 "漏标"

文章配图

(2)问题解决方案
  • 多标(浮动垃圾):
    • 原因:并发标记中,GC Roots 销毁导致部分对象失去引用但已标记
    • 影响:不影响正确性,需下次 GC 清理
    • 处理:新对象直接标记为黑色(本轮不清理)
  • 漏标(严重 bug):
    • 原因:并发标记中,对象引用关系变化导致部分可达对象未标记
    • 解决方案:
      1. 增量更新(CMS 使用):黑色对象新增指向白色对象的引用时,记录引用并重新扫描
      2. 原始快照(SATB,G1/Shenandoah 使用):灰色对象删除指向白色对象的引用时,记录引用并重新扫描
(3)实现机制:读写屏障
  • 写屏障:赋值操作前后插入处理逻辑(AOP 思想)
    • 增量更新:post_write_barrier记录新引用对象
    • SATB:pre_write_barrier记录旧引用对象
  • 读屏障:读取成员变量前插入处理逻辑(ZGC 使用),记录读取的对象
  • 代码模型:
// 写屏障示例
void oop_field_store(oop* field, oop new_value) {
    pre_write_barrier(field); // SATB 记录旧值
    *field = new_value;
    post_write_barrier(field, new_value); // 增量更新记录新值
}

// 读屏障示例
oop oop_field_load(oop* field) {
    pre_load_barrier(field); // 记录读取对象
    return *field;
}
2. 记忆集与卡表(跨代引用优化)
(1)核心问题
  • 新生代 GC 时,需扫描老年代中指向新生代的跨代引用(直接扫描老年代效率低)
(2)记忆集(Remember Set)
  • 数据结构:记录从非收集区到收集区的指针集合
  • 作用:避免扫描整个非收集区,仅需处理记忆集中的跨代引用
(3)卡表(Card Table)
  • 实现方式:字节数组 CARD_TABLE[],每个元素对应 512 字节(2^9)的 "卡页"
  • 标记规则:卡页中存在跨代引用时,对应元素设为 1(变脏),否则为 0
  • 维护机制:通过写屏障触发卡表更新

文章配图

四、JVM 参数优化实战(ParNew+CMS)

1. 亿级流量订单系统场景
  • 硬件配置:4 核 8G 服务器,JVM 分配 4G 内存
  • 业务特征:每秒产生 60MB 对象,大促峰值 300 单 / 秒
  • 核心目标:减少 Full GC 频率,控制 STW 时间
2. 优化后参数配置
-Xms3072M -Xmx3072M # 堆内存固定 3G(避免动态扩容)
-Xmn2048M # 新生代 2G(占堆 66.7%,减少 Minor GC 频率)
-Xss1M # 线程栈大小
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M # 元空间固定
-XX:SurvivorRatio=8 # Eden:S0:S1=8:1:1
-XX:MaxTenuringThreshold=5 # 对象 5 次 Minor GC 后进入老年代
-XX:PretenureSizeThreshold=1M # 1M 以上大对象直接进入老年代
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC # 启用 ParNew+CMS
-XX:CMSInitiatingOccupancyFraction=92 # 老年代使用率 92% 触发 Full GC
-XX:+UseCMSCompactAtFullCollection # Full GC 后整理碎片
-XX:CMSFullGCsBeforeCompaction=3 # 3 次 Full GC 后整理一次
3. 优化思路解析
  • 新生代扩容:减少 Minor GC 次数,避免对象频繁进入老年代
  • 调整对象晋升年龄:短期存活对象(几秒内)在 Minor GC 中回收
  • 大对象直接进入老年代:避免新生代复制开销

CMS 参数优化:平衡 Full GC 频率与碎片整理开销

文章配图

目录

  1. 一、垃圾收集算法
  2. 1. 分代收集理论
  3. 2. 三大基础垃圾收集算法
  4. (1)标记 - 复制算法
  5. (2)标记 - 清除算法
  6. (3)标记 - 整理算法
  7. 3. 算法对比总结
  8. 二、垃圾收集器
  9. 1. 收集器分类与核心特性
  10. (1)新生代收集器
  11. (2)老年代收集器
  12. 2. 重点收集器详解
  13. (1)Serial 收集器(串行收集器)
  14. (2)Parallel 系列收集器(吞吐量优先)
  15. (3)ParNew 收集器(CMS 配套)
  16. (4)CMS 收集器(低停顿优先)
  17. 3. 收集器选择原则
  18. 三、底层核心机制
  19. 1. 三色标记算法(并发标记核心)
  20. (1)核心概念
  21. (2)问题解决方案
  22. (3)实现机制:读写屏障
  23. 2. 记忆集与卡表(跨代引用优化)
  24. (1)核心问题
  25. (2)记忆集(Remember Set)
  26. (3)卡表(Card Table)
  27. 四、JVM 参数优化实战(ParNew+CMS)
  28. 1. 亿级流量订单系统场景
  29. 2. 优化后参数配置
  30. 3. 优化思路解析

更多推荐文章

查看全部
  • ctypes 调用 C++ 动态库:从编译到踩坑
  • Python 实现屏幕爱心弹窗效果
  • LLM 大模型应用开发:原理、实践与框架指南
  • 大模型在企业落地的路径与价值实践
  • C 语言指针与复杂数据结构:链表、栈与队列实现
  • 基于FPGA的五级CIC滤波器Verilog设计与实现
  • 基于 Leaflet 和天地图的长沙市免费运动场所 WebGIS 可视化
  • 如何选择最适合您需求的向量数据库
  • Web 应用全栈开发实战笔记
  • 多端多接口多向传导空战数据链体系:异构融合与抗毁弹性网络设计
  • 在 Cursor 中配置并使用 MCP 服务实战
  • 组合数学入门:核心概念与 4 种求组合数方法
  • Windows 下安装 OpenClaw 并接入飞书机器人指南
  • 《Agent Runtime 工程化》第一章 Agent Runtime 全景:1.1 Agent、Workflow、Tool、Runtime 的边界
  • macOS 使用 Homebrew 安装 MySQL 指南
  • Milvus 部署架构选型与 Linux Docker 实战指南
  • AI 辅助编程的边界探索:当 Copilot 学会写测试
  • Mac mini M4 本地部署 OpenClaw + Ollama 接入飞书机器人实战
  • MySQL 面试核心考点:架构、索引与事务实战
  • RFC4291 IPv6 地址架构

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online