1. CMS GC内存结构简述
JVM堆内存主要分为:
- 新生代(Young Generation):包括 Eden 区和两个 Survivor 区(S0/S1)
- 老年代(Old Generation)
- (还有永久代/元空间,但与 CMS GC 配置比例关系较小)
CMS GC主要作用于老年代,而新生代通常由 ParNew GC 回收。
2. 主要配置参数
2.1 总堆内存大小
-Xms<size> # 初始堆大小
-Xmx<size> # 最大堆大小
2.2 新生代大小
-Xmn<size> # 新生代大小(包括Eden和Survivor区)
2.3 新生代与老年代比例
- 新生代大小 =
-Xmn - 老年代大小 = 总堆大小 - 新生代大小
例如:
-Xmx4g -Xms4g -Xmn1g
表示总堆4G,其中新生代1G,老年代3G。
2.4 Eden与Survivor比例
-XX:SurvivorRatio=<N>
Eden区与每个Survivor区的比例。例如:
-XX:SurvivorRatio=8表示 Eden : S0 : S1 = 8 : 1 : 1
2.5 新生代与老年代比例(另一种方式)
如果不指定-Xmn,可以通过下面参数控制比例:
-XX:NewRatio=<N>
表示老年代:新生代的比例。例如:
-XX:NewRatio=2表示老年代是新生代的2倍(即新生代占1/3,老年代占2/3)
3. CMS GC相关参数
启用CMS GC:
-XX:+UseConcMarkSweepGC
常用配合参数:
-XX:CMSInitiatingOccupancyFraction=<N> # 老年代使用率到N%时触发CMS
-XX:+UseCMSInitiatingOccupancyOnly # 只用上述阈值触发CMS
4. 配置举例
举例1:指定新生代大小
-Xms8g -Xmx8g -Xmn2g -XX:+UseConcMarkSweepGC
- 堆总大小8G
- 新生代2G
- 老年代6G
举例2:通过比例配置
-Xms8g -Xmx8g -XX:NewRatio=3 -XX:+UseConcMarkSweepGC
- 新生代占1/4(2G),老年代占3/4(6G)
5. 选择建议
- 大对象多/存活对象多:新生代可以适当调小,老年代调大。
- 大量短生命周期对象:新生代调大,减少晋升老年代频率。
- CMS GC适合老年代回收耗时敏感场景。
6. 其他补充
- CMS GC在JDK9及以后被标记为废弃,推荐使用G1 GC。
- CMS GC对内存比例配置非常敏感,建议根据实际业务压力和GC日志反复调优。
7. CMS GC内存比例调优思路
7.1 新生代与老年代比例调优原则
- 新生代较大:适合大量短命对象,减少Minor GC频率,但晋升老年代的对象会多。
- 老年代较大:适合大量长寿命对象,减少Full GC频率,但Minor GC可能更频繁。
调优目标:
- Minor GC频率适中,停顿时间短。
- 老年代不容易被填满,避免频繁Full GC或CMS GC。
- 晋升失败(Promotion Failed)或Concurrent Mode Failure尽量避免。
7.2 配置参数优先级
-Xmn(新生代大小)和-XX:NewRatio(比例)只用其一,-Xmn优先生效。- 推荐直接用
-Xmn,便于精确控制。
8. Survivor区比例的调优
- Eden与Survivor区比例通过
-XX:SurvivorRatio控制。 - 默认是8,即Eden:S0:S1=8:1:1。
- Survivor区过小可能导致对象过早晋升到老年代,过大则浪费新生代空间。
调优建议:
- 观察GC日志中“对象在Survivor区存活次数”,适当调整Survivor区大小,减少对象早晋升。
9. CMS相关其他重要参数
-
-XX:CMSInitiatingOccupancyFraction=75
老年代使用率达到75%时触发CMS GC,默认是68%。 -
-XX:+UseCMSInitiatingOccupancyOnly
只用上述阈值,不用JVM自适应策略。 -
-XX:MaxTenuringThreshold=15
新生代对象晋升到老年代的最大存活次数(默认15)。
10. 常见内存配置问题及排查
10.1 新生代过小
表现:
- Minor GC频繁,吞吐量低。
- 新生代对象大量晋升到老年代,老年代很快被填满。
解决:
- 增大
-Xmn或调小-XX:NewRatio。
10.2 老年代过小
表现:
- CMS GC频繁,甚至出现Concurrent Mode Failure(并发模式失败)。
- 老年代OOM。
解决:
- 增大堆总量或减少新生代比例。
10.3 Survivor区过小
表现:
- 新生代对象无法在Survivor区多次存活,过早晋升老年代。
解决:
- 调小
-XX:SurvivorRatio(如从8调到6)。
11. 实际调优流程
-
收集GC日志
打开GC详细日志,分析Minor GC和Full GC频率、耗时、晋升情况。 -
分析对象分布
用jmap -heap、jstat -gc、VisualVM等工具查看堆内存使用和对象年龄分布。 -
调整参数
- Minor GC频繁 → 增大新生代
- Full GC频繁或CMS失败 → 增大老年代
- 晋升过快 → 增大Survivor区
-
反复验证
每次调整后观察一段时间,反复迭代。
12. 配置案例对比
案例1:大新生代,适合高并发短生命周期对象
-Xms8g -Xmx8g -Xmn4g -XX:SurvivorRatio=6 -XX:+UseConcMarkSweepGC
- 新生代4G,老年代4G
- Survivor区比例6:1:1,便于对象多次存活
案例2:大老年代,适合长生命周期对象
-Xms8g -Xmx8g -Xmn2g -XX:SurvivorRatio=8 -XX:+UseConcMarkSweepGC
- 新生代2G,老年代6G
- Survivor区比例8:1:1,适合对象早晋升
13. 线上环境运维建议
- 定期分析GC日志,关注CMS GC耗时、频率、是否有Concurrent Mode Failure
- 内存配置要留冗余,避免极限压榨
- CMS GC已被JDK9+废弃,建议新项目用G1 GC
14. 自动化调优与监控建议
14.1 自动化调优思路
- 利用A/B测试或灰度发布,观察不同内存比例下GC行为。
- 结合监控系统(如Prometheus + Grafana、ELK)实时采集GC日志和JVM内存指标。
- 设定报警阈值(如Full GC次数、CMS失败、堆使用率过高),自动触发运维通知。
14.2 关键监控指标
- Minor GC/Full GC次数与耗时
- 老年代使用率变化
- 晋升失败/Concurrent Mode Failure次数
- 应用响应时间与吞吐量
15. 典型问题及处理
15.1 CMS Concurrent Mode Failure
原因:
- CMS并发回收时,老年代被填满,导致JVM不得不STW进行标记和清理。
处理方法:
- 增大老年代(减小新生代或增大堆总量)
- 提前触发CMS GC(降低
-XX:CMSInitiatingOccupancyFraction) - 优化业务代码减少大对象或长生命周期对象
15.2 晋升失败(Promotion Failed)
原因:
- 新生代GC后,晋升到老年代的对象超过老年代剩余空间。
处理方法:
- 增大老年代
- 优化对象生命周期,减少晋升频率
- 增加Survivor区大小,让对象多存活几次,避免过早晋升
15.3 内存碎片化
CMS GC是标记-清除算法,容易造成老年代内存碎片。
- 可用
-XX:+UseCMSCompactAtFullCollection在每次Full GC后做老年代压缩,但会增加停顿时间。
16. 与其他JVM参数的协同关系
16.1 -XX:MaxTenuringThreshold
- 控制对象在Survivor区存活几次后晋升老年代。
- 较大值适合对象生命周期分布广的场景,较小值适合对象寿命短的场景。
16.2 -XX:PretenureSizeThreshold
- 超过该大小的新对象直接分配到老年代,适合大对象场景。
- 结合CMS GC可减少新生代GC压力。
16.3 -XX:CMSInitiatingOccupancyFraction 和 -XX:+UseCMSInitiatingOccupancyOnly
- 控制老年代使用率达到多少时触发CMS GC。
- 配合业务高峰期提前GC,防止老年代爆满。
17. CMS GC与G1 GC的迁移建议
- CMS GC在JDK9及以后已废弃,官方推荐使用G1 GC。
- G1 GC不需要手动区分新生代/老年代,自动分配和回收。
- 如果你的应用升级JDK,建议切换到G1 GC,简化内存调优。
G1 GC典型配置:
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
G1 GC会自动根据Pause目标和堆使用率动态调整内存比例。
18. 生产环境配置建议
- 预留足够堆空间,不要把物理内存用到极限,留出操作系统和其他进程空间。
- 分阶段逐步调优,每次调整只改一个参数,观察效果。
- 定期回顾GC日志,分析GC行为变化,防止参数老化。
- 准备OOM应急方案,如自动重启、内存转储、报警通知。
总结
CMS GC新生代与老年代的内存比例,主要通过 -Xmn 或 -XX:NewRatio 参数配置。
-Xmn明确指定新生代大小-XX:NewRatio按比例指定新生代和老年代大小
CMS GC内存比例的核心调优点:
- 通过
-Xmn/-XX:NewRatio控制新生代与老年代比例 - 通过
-XX:SurvivorRatio控制Eden与Survivor比例 - 结合GC日志、对象分布和业务特性反复调优
CMS GC内存比例配置是性能调优的核心环节,涉及新生代、老年代、Survivor区的合理分配,以及与晋升、回收、碎片等问题的协同调优。
随着JDK版本升级,建议逐步迁移到G1 GC,简化配置和运维压力。

438

被折叠的 条评论
为什么被折叠?



