提升JVM性能之CMS垃圾回收器的优化分析与案例剖析

这里写目录标题

      • 一、CMS基本介绍
      • 二、CMS核心优化策略
        • 1. 避免并发模式失败(Concurrent Mode Failure)
        • 2. 减少内存碎片
        • 3. 调优并发阶段耗时
        • 4. 新生代优化配合
      • 三、典型案例解析
        • 案例1:电商服务频繁Full GC
        • 案例2:金融交易系统碎片导致长时间停顿
      • 四、关键参数清单
      • 五、升级替代方案
      • 六、调优流程

优化CMS垃圾回收器(Concurrent Mark-Sweep)是提升JVM性能的关键手段,尤其适用于追求低延迟的老年代回收场景。以下结合核心优化策略与真实案例,为你提供系统化的解决方案:


一、CMS基本介绍

核心目标: CMS 垃圾回收器的主要设计目标是 最小化垃圾回收导致的应用程序停顿时间(Stop-The-World, STW)。它特别适用于那些对响应时间敏感的应用程序,例如 Web 服务器、GUI 桌面应用、API 服务等。

核心特点: 并发标记和清除

CMS 的核心在于它的大部分工作(标记和清除阶段)是与用户线程并发执行的,大大减少了 STW 的时间。这也是它被称为“并发”收集器的原因。

工作流程(四个主要阶段):

  1. 初始标记(Initial Mark - STW):

    • 这是第一个短暂的 STW 阶段。
    • 目标:快速标记所有直接从 GC Roots(如线程栈变量、静态变量、JNI 引用等)直接可达的存活对象
    • 为什么快?因为它只标记直接关联的对象,不进行深度扫描。
    • 停顿时间通常很短。
  2. 并发标记(Concurrent Mark):

    • 最重要的并发阶段。
    • 目标:沿着初始标记阶段标记出的存活对象图,深度遍历整个老年代对象图,标记所有可达的(存活的)对象。
    • 关键点: 这个阶段与用户线程并发执行。用户线程仍在运行,可能会修改对象的引用关系(导致新对象产生或旧对象不可达)。
    • 因为并发,此阶段耗时较长,但不会暂停应用。
  3. 重新标记(Remark - STW):

    • 第二个(通常也是较长的)STW 阶段。
    • 目标:修正在并发标记阶段,由于用户线程继续运行而导致发生变化的引用关系(即标记那些在并发标记过程中新产生的垃圾或新晋升为存活的对象)。CMS 使用了一些技术(如增量更新或原始快照)来高效地完成这个修正工作。
    • 虽然需要 STW,但 CMS 通过各种优化手段(如预清理、卡表)尽量缩短这个阶段的时间。
    • 停顿时间比初始标记长,但远小于并发标记的总时间(因为并发标记不暂停)。
  4. 并发清除(Concurrent Sweep):

    • 第三个并发阶段。
    • 目标:回收在标记阶段被确定为不可达(垃圾)的对象所占用的内存空间
    • 关键点: 这个阶段与用户线程并发执行。用户线程可以继续分配新对象。
    • 回收后的内存空间不会立即进行压缩整理,因此是空闲列表(Free List)管理。

关键优势和适用场景:

  • 低延迟/短停顿: 最大的优势!通过并发执行大部分耗时的标记和清除工作,显著减少了 STW 的总时间,使得应用程序响应更流畅。
  • 适合交互式应用: 对用户交互响应时间要求高的场景(如 GUI 程序、Web 请求响应)。
  • 老年代收集器: CMS 主要用来回收老年代的对象。它通常需要与一个负责新生代回收的收集器(最常见的是 ParNew)配合使用。

主要缺点和挑战:

  1. CPU 资源敏感:

    • 在并发标记和并发清除阶段,垃圾回收线程会与用户线程竞争 CPU 资源。如果 CPU 资源紧张,可能导致应用程序吞吐量下降。
    • 默认的回收线程数 = (CPU 核心数 + 3)/4。在 CPU 核心数少的情况下,并发回收线程可能占用过多 CPU。
  2. 无法处理“浮动垃圾”(Floating Garbage):

    • 在并发标记阶段,用户线程还在运行,可能产生新的垃圾对象(标记阶段结束后才成为垃圾)或使一些已标记的对象变为垃圾。
    • 这些垃圾(浮动垃圾)无法在当前回收周期被清除,只能留到下一次 GC。
    • 这可能导致需要预留更多空间(-XX:CMSInitiatingOccupancyFraction 参数设置触发阈值,如 70%),以防在回收完成前老年代就满了。
  3. “并发模式失败”(Concurrent Mode Failure):

    • 最严重的问题! 如果在 CMS 执行过程中(特别是并发阶段),老年代空间不足以容纳从新生代晋升上来的对象或者新分配的大对象,JVM 就会被迫中断 CMS 的并发回收过程。
    • 此时,JVM 会触发一次 Serial Old(单线程)Full GC。这是一个非常耗时的 STW 过程,会暂停所有用户线程,并对整个堆(包括新生代和老年代)进行标记-清除-压缩。这与使用 CMS 的初衷(低延迟)背道而驰。
    • 触发原因通常是:老年代空间预留不足(触发阈值设置过高)、晋升过快、大对象过多、内存碎片严重导致无法分配连续空间。
  4. 内存碎片(Memory Fragmentation):

    • CMS 采用的是 标记-清除(Mark-Sweep)算法,而不是标记-整理(Mark-Compact)。它只清除垃圾对象,不移动存活对象进行内存压缩
    • 经过多次回收后,老年代会产生大量不连续的内存碎片。当需要分配一个较大连续内存空间的对象时,即使总的剩余空间足够,也可能因为找不到足够大的连续空间而触发 Full GC(通常是 Serial Old) 来进行压缩整理。
    • 为了缓解碎片,CMS 提供了 -XX:+UseCMSCompactAtFullCollection(在 Full GC 时压缩,默认开启)和 -XX:CMSFullGCsBeforeCompaction(执行多少次不压缩的 Full GC 后,再执行一次带压缩的 Full GC,默认为 0,表示每次进入 Full GC 都压缩)参数,但这又会带来更长的 STW 时间。
  5. 对新生代回收器的依赖: CMS 本身不管理新生代,必须配合一个新生代收集器(如 ParNew、Serial)。如果新生代 GC 频繁或耗时长,也会间接影响整体停顿时间。

二、CMS核心优化策略

1. 避免并发模式失败(Concurrent Mode Failure)
  • 问题本质:CMS并发清理时,老年代空间不足以容纳新晋升对象,触发Full GC(Stop-The-World)。
  • 优化方案
    • 增大老年代空间(-XX:NewRatio 调整新生代/老年代比例)
    • 降低对象晋升速度:
      -XX:MaxTenuringThreshold=6      # 提高对象在新生代存活次数
      -XX:+UseCMSInitiatingOccupancyOnly
      -XX:CMSInitiatingOccupancyFraction=70  # 老年代70%时启动CMS
      
2. 减少内存碎片
  • 启用压缩
    -XX:+UseCMSCompactAtFullCollection   # Full GC后压缩内存
    -XX:CMSFullGCsBeforeCompaction=2     # 每2次Full GC压缩一次
    
3. 调优并发阶段耗时
  • 缩短初始标记(STW阶段)
    -XX:+CMSParallelInitialMarkEnabled  # 并行初始标记
    
  • 并发标记/清理线程数
    -XX:ConcGCThreads=4  # 推荐为CPU核数的1/4
    
4. 新生代优化配合
  • 选择合适的新生代回收器
    -XX:+UseParNewGC  # CMS默认搭配ParNew
    
  • 调整Eden/Survivor
    -XX:SurvivorRatio=8  # Eden与Survivor比例
    

三、典型案例解析

案例1:电商服务频繁Full GC
  • 现象:高峰期每10分钟发生Concurrent Mode Failure,停顿2秒。
  • 原因分析
    • 老年代大小固定为2GB,CMSInitiatingOccupancyFraction=68
    • 日志显示并发阶段未完成时老年代已满
  • 优化措施
    -XX:CMSInitiatingOccupancyFraction=60  # 更早启动CMS
    -XX:NewRatio=3                         # 老年代从2GB→3GB
    -XX:MaxTenuringThreshold=8             # 减少短期对象晋升
    
  • 结果:Full GC消失,平均延迟下降65%
案例2:金融交易系统碎片导致长时间停顿
  • 现象:每日凌晨Full GC耗时8秒,影响结算流程。
  • 原因分析
    • CMSFullGCsBeforeCompaction=0(默认每次Full GC都压缩)
    • 内存碎片率达40%
  • 优化措施
    -XX:CMSFullGCsBeforeCompaction=4     # 减少压缩频率
    -XX:+UseCMSInitiatingOccupancyOnly
    -XX:CMSInitiatingOccupancyFraction=50 # 预留更多空间防失败
    
  • 结果:Full GC时间降至1.5秒,碎片率<15%

四、关键参数清单

参数建议值作用
-XX:+UseConcMarkSweepGC必启用启用CMS
-XX:CMSInitiatingOccupancyFraction60-75老年代触发回收阈值
-XX:+UseCMSInitiatingOccupancyOnly必启用避免JVM动态调整阈值
-XX:ConcGCThreadsCPU核数/4并发线程数
-XX:+CMSScavengeBeforeRemark推荐启用重新标记前Young GC

五、升级替代方案

若优化后仍不满足需求(如堆>8GB或停顿>200ms),考虑迁移至:

  1. G1垃圾回收器
    -XX:+UseG1GC -XX:MaxGCPauseMillis=200
    
  2. ZGC(JDK11+):
    -XX:+UseZGC -Xmx16g  # 亚毫秒级停顿
    

六、调优流程

  1. 监控诊断
    -Xlog:gc*:file=gc.log  # JDK9+统一日志
    jstat -gcutil <pid> 1000
    
  2. 分析工具
    • GCViewer 分析日志
    • Eclipse Memory Analyzer 排查内存泄露
  3. 压测验证
    jmeter -n -t test.jmx # 模拟流量验证优化效果
    

关键建议:CMS优化需结合对象生命周期分析(JProfiler)与压力测试,避免仅凭经验调整。对于新项目,优先选择G1或ZGC以规避CMS碎片问题。

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

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

相关文章

Token系列 - 再谈稳定币

相关政策 2024年12月&#xff0c;欧洲《加密资产市场监管法案》正式成为法律2025年3月&#xff0c;日本细化了加密资产及稳定币的监管调整2025年5月&#xff0c;英国发布了关于稳定币发行、加密资产托管及加密资产公司财务稳健性的监管提案&#xff1b;2025年5月20日&#xff…

【20min 急速入门】使用Demucs进行音轨分离

创建环境 conda create --name mujica python3.10下载加速依赖 先用nvidia-smi检查机器使用的独显版本, 然后从pytorch官网下载对应的GPU版torch, torchaudio 比如我的是12.2, 就下载11.8版本的 pip3 install torch torchvision torchaudio --index-url https://download.p…

字节Seed发布扩散语言模型,推理速度达2146 tokens/s,比同规模自回归快5.4倍

用扩散模型写代码&#xff0c;不仅像开了倍速&#xff0c;改起来还特别灵活&#xff01;字节Seed最新发布扩散语言模型Seed Diffusion Preview&#xff0c;这款模型主要聚焦于代码生成领域&#xff0c;它的特别之处在于采用了离散状态扩散技术&#xff0c;在推理速度上表现出色…

海洋大地测量基准与水下导航系列之九我国海洋PNT最新技术进展(下)

三、海洋PNT技术装备研发与工程化应用 1.海底基准装备 研制了首批适应海洋环境的多型海底基准站装备&#xff0c;在我国南海海域成功布设了定位精度优于0.25m的海底大地测量试验基准网&#xff0c;实现了我国海底大地测量基准技术零的突破。基准方舱具备稳固、抗压、防腐、防…

入门MicroPython+ESP32:安装逗脑IDE及驱动

本篇文章将手把手带大家入门MicroPython ESP32&#xff0c;重点介绍逗脑IDE的安装过程以及相关驱动的安装。 一、下载逗脑IDE 要开始使用逗脑IDE&#xff0c;首先需要从官网下载最新版本。请访问以下网址进行下载&#xff1a;https://www.itprojects.cn/ide 下载时的界面大…

CentOS上部署Redis及其哨兵(Sentinel)模式

架构&#xff1a;说明我这里是伪集群的&#xff0c;redis 在同一台机器&#xff0c;Sentinel 只有一个&#xff0c;也存在单点故障问题只能当作开发环境使用&#xff0c;要满足生产至少是下面这种架构 ------------------- ------------------- ------------------- …

《软件测试与质量控制》实验报告二 单元测试

目 录 一、实验学时 二、实验目的 三、实验环境 &#xff08;一&#xff09;硬件环境&#xff1a; &#xff08;二&#xff09;软件环境&#xff1a; 四、实验内容 1、实验方案&#xff1a; 2、实验步骤&#xff1a; 3、设计思路&#xff1a; 1、安装JUnit和Eclemma…

k8s模式部署PolarDB-X

当前文档适配PolarDB-X V2.4.0 版本 环境描述&#xff1a; 部署机&#xff08;ops&#xff09;1x2.2x.2x8.116&#xff0c;部署机需要可以访问互联网。使用ansible进行部署&#xff0c;自行安装ansible。需要部署两个k8s集群&#xff0c;分别在其上安装一个polardb-x集群。 部…

Flask + YARA-Python*实现文件扫描功能

以下是一个 完整的 Web API 示例&#xff0c;使用 Flask YARA-Python 实现文件扫描功能&#xff0c;支持上传文件并返回 YARA 规则匹配结果。 ✅ 功能说明 提供一个 /scan 接口&#xff0c;支持文件上传使用预加载的 YARA 规则进行扫描返回 JSON 格式的匹配结果支持多规则、可…

WinForm之NumericUpDown控件

NumericUpDown&#xff08;数字上下控件&#xff09;是 WinForm 中专门用于输入和调整数值的控件&#xff0c;它结合了文本框和上下按钮&#xff0c;用户可通过点击按钮或直接输入来设置数值&#xff0c;且能严格限制数值范围&#xff08;最小值、最大值&#xff09;和步长&…

一文读懂K8S kubectl 命令,运维小白必看!

一、Kubectl 是什么? Kubectl 是 Kubernetes(简称 K8S)集群的命令行工具,它就像是一把万能钥匙,让我们可以与 K8S 集群进行交互,轻松管理集群中的各种资源,像是 Pod、Service、Deployment 等等。通过向 K8S API 发送 REST 请求,kubectl 实现了对集群资源的增删改查等操…

髋臼方向的定义与测量-I

近期看到关于髋臼方向不同应用场景下的不同定义&#xff0c;觉得特别有意思&#xff0c;但是&#xff0c;原文是影印本&#xff0c;不太方便实用屏幕取词翻译&#xff0c;且一些专业术语也不太好理解。 因此&#xff0c;我将原文和翻译整理了一些&#xff0c;不对的地方&#x…

Python爬虫实战:研究mahotas库,构建图像获取及处理系统

一、引言 (一)研究背景 在信息爆炸的时代,图像作为一种直观、丰富的信息载体,其数量在互联网上呈现指数级增长。这些图像数据涵盖了自然景观、动植物、工业产品等多个领域,为模式识别、机器学习等研究提供了宝贵的数据源。特别是在植物学研究领域,叶片图像包含了丰富的…

【04】海康相机C#开发——VS 在编译时,提示“Files的值“+乱码情况解决办法’ ,C#项目打开编译时报错:Files 的值“IGEF‘,

文章目录C#项目打开&#xff0c;用VS 在编译时编译时报错&#xff1a;Files 的值“乱码&#xff1b; 有的编译器会显示&#xff1a;Files的值“IGEF 以上报错都为同一种错误&#xff0c;.net中的配置文件乱码导致的&#xff1a; 找到项目目录下的“..\obj\Debug\”的文件夹中…

MySQL隐式转换陷阱:从错误查询案例解析索引失效与数据类型匹配

开始之前&#xff0c;先问个问题问题&#xff1a;mysql 数据类型是date &#xff0c;怎么写查询条件索引有效&#xff1f; ——下面带着疑问看下去。 一、mysql-8.隐式转换导致索引失效或查出不符合where条件结果 今天在执行一条sql语句时候&#xff0c;where条件写错了&#x…

【sklearn(01)】数据集加载、划分,csv文件创建,特征工程,无量纲化

目录sklearn数据集玩具数据集现实世界数据集加载玩具数据集获取现实世界数据集本地csv数据创建csv文件pandas加载csv数据集划分特征工程步骤特征工程APIDictVectorizer 字典列表特征提取APICountVectorizer 文本特征提取API英文文本提取中文文本提取TfidfVectorizer TF-IDF文本…

docker desktop入门(docker桌面版)(提示wsl版本太低解决办法)

参考文章&#xff1a;Docker Desktop Engine Stopped原因分析&#xff08;docker桌面停止&#xff09;WSL没装或没更新 文章目录Docker Desktop入门指南1. Docker Desktop简介2. 安装Docker Desktop2.1 系统要求2.2 下载和安装3. 配置Docker Desktop修改默认存储路径4. 运行你的…

《n8n基础教学》第三节:模拟一个自动化场景

1、模拟场景Nathan &#x1f64b;是 ABCorp 的分析经理&#xff0c;他的工作是支持 ABCorp 团队的报告和分析。作为一个真正的多面手&#xff0c;他还负责处理一些杂项任务。Nathan 做的一些事情是重复且枯燥的。他希望自动化其中一些任务&#xff0c;以避免精疲力竭。作为一名…

CodeRush AI 助手进驻 Visual Studio:AiGen/AiFind 亮相(三)

CodeRush 是专为 Visual Studio 打造的高效开发插件&#xff0c;通过集成 AI 驱动功能&#xff08;如自然语言生成代码的 AiGen 和智能搜索逻辑的 AiFind&#xff09;、语音交互及深度重构工具&#xff0c;直接在 IDE 内无缝完成代码生成、修改与导航&#xff0c;消除窗口切换与…

如何从头开始搭建属于自己的家用nas实现内网穿透访问

最近我在家部署了群晖NAS923&#xff0c;从而实现内网穿透&#xff0c;下面写一个新手向教程&#xff1a; 一、硬件安装与初始化设置 1. 硬盘安装&#xff08;已完成可跳过&#xff09; 群晖 923 支持 4 块 3.5 英寸硬盘&#xff0c;开箱后取出硬盘架&#xff0c;将硬盘&am…