云计算、AI、云原生、大数据等一站式技术学习平台

网站首页 > 教程文章 正文

GC优化实战:CMS vs G1(g1比cms高效的原因)

jxf315 2025-06-08 22:08:41 教程文章 32 ℃

背景

因cms的内存碎片问题,j8开始已不推荐使用,14开始被废弃,最近在生产的一个job服务其中2台服务器调整成了g1,但通过监控发现不太理想,趁着暂时有空来优化一波。

服务器监控

同样的硬件配置,同样的java应用,cms比g1cpu使用率低1%左右,内存使用率低了10%+

原因分析

为保险起见,jmap拿到dump文件后分析无可疑对象

搜索分析得到的可能原因:

CMS是并发标记清除,主要针对老年代,而G1是分区域收集,兼顾新生代和老年代,目标是低延迟和高吞吐。G1的内存管理方式不同,将堆分成多个Region,可能因此内存开销更大,导致内存使用率较高。内存使用率差异10%,可能和G1的Region管理、记忆集(RSet)等有关。

JVM启动参数对比

nohup java -jar -Xmx10G -Xms10G \
        -XX:SurvivorRatio=2 -XX:NewRatio=8 -XX:MaxTenuringThreshold=15 -XX:+UseConcMarkSweepGC -XX:CMSMaxAbortablePrecleanTime=5000 -XX:+CMSClassUnloadingEnabled -XX:CMSInitiatingOccupancyFraction=50 -XX:+UseCMSInitiatingOccupancyOnly \
        -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -XX:ReservedCodeCacheSize=256M \
        -XX:CMSFullGCsBeforeCompaction=10 -XX:+CMSScavengeBeforeRemark \
        -XX:+ExplicitGCInvokesConcurrent -Dsun.rmi.dgc.server.gcInterval=2592000000 -Dsun.rmi.dgc.client.gcInterval=2592000000 -Xloggc:./gc.log -XX:NumberOfGCLogFiles=5  -XX:GCLogFileSize=50M  -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./dump.hprof \		
nohup java -jar -Xmx10G -Xms10G \
        -XX:+UseG1GC \
        -XX:+UnlockExperimentalVMOptions \
        -XX:G1NewSizePercent=40 -XX:G1MaxNewSizePercent=40 -XX:MaxTenuringThreshold=8 -XX:G1ReservePercent=20 \
        -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -XX:ReservedCodeCacheSize=128M \
        -XX:MaxGCPauseMillis=200 -XX:G1HeapWastePercent=10 -XX:G1MixedGCCountTarget=12  \
        -XX:G1HeapRegionSize=8m \
        -XX:ConcGCThreads=4 \
        -XX:ParallelGCThreads=4 \
        -XX:MaxDirectMemorySize=1g \
        -XX:-UseStringDeduplication \
        -XX:StringDeduplicationAgeThreshold=3 \
        -XX:+ParallelRefProcEnabled \
        -XX:+PrintCompilation \
        -XX:InitiatingHeapOccupancyPercent=45 \
        -Xloggc:gc.log -XX:NumberOfGCLogFiles=5  -XX:GCLogFileSize=50M  -XX:+PrintGCDetails -XX:+PrintGCDateStamps \
        -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./dump.hprof \

优化措施-2025-05-09

一、内存使用率优化

1. 调整Region大小与保留空间

当前配置-XX:G1HeapRegionSize=8m可能产生内存浪费:

建议改为-XX:G1HeapRegionSize=4m(或2MB),小Region能更灵活分配内存,减少大对象(Humongous对象)导致的跨区域浪费

降低-XX:G1ReservePercent=20至10%:-XX:G1ReservePercent=10,减少预留空间占用(原始CMS无类似机制)

2. 优化新生代比例

当前-XX:G1NewSizePercent=40

改为-XX:G1NewSizePercent=50和-XX:G1MaxNewSizePercent=50,

移除-XX:MaxTenuringThreshold=8恢复默认15,降低对象晋升频率

3. 启用字符串去重

添加-XX:+UseStringDeduplication,可减少重复字符串内存占用(需JDK8u20+),配合
-XX:StringDeduplicationAgeThreshold=3效果更佳


二、CPU使用率优化

1. 调整GC线程策略

当前-XX:ConcGCThreads=4可能过低:

根据CPU核数优化:若物理核≥8,建议-XX:ParallelGCThreads=8和-XX:ConcGCThreads=4(保持1:2比例)

添加-XX:+ParallelRefProcEnabled加速引用处理

2. 优化混合GC策略

调整混合回收参数:


-XX:G1MixedGCLiveThresholdPercent=85 # 提高存活对象阈值(默认85)

-XX:G1HeapWastePercent=5 # 降低回收浪费阈值(原10)

-XX:G1MixedGCCountTarget=8 # 减少混合GC次数(原12)


调整后的参数

nohup java -jar -Xmx10G -Xms10G \
        -XX:+UseG1GC \
        -XX:+UnlockExperimentalVMOptions \
        -XX:G1NewSizePercent=50 -XX:G1MaxNewSizePercent=50 -XX:MaxTenuringThreshold=15 -XX:G1ReservePercent=10 \
        -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -XX:ReservedCodeCacheSize=128M \
        -XX:MaxGCPauseMillis=200 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=8  \
        -XX:G1HeapRegionSize=4m \
        -XX:ConcGCThreads=4 \
        -XX:ParallelGCThreads=8 \
        -XX:MaxDirectMemorySize=1g \
        -XX:+UseStringDeduplication \
        -XX:StringDeduplicationAgeThreshold=3 \
        -XX:+ParallelRefProcEnabled \
        -XX:+PrintCompilation \
        -XX:InitiatingHeapOccupancyPercent=45 \
        -Xloggc:./gc.log -XX:NumberOfGCLogFiles=5  -XX:GCLogFileSize=50M  -XX:+PrintGCDetails -XX:+PrintGCDateStamps \
        -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./dump.hprof \

对137.89做调整,136.89保持原参数做比对

半小时后

内存下降明显

1小时后

后续持续监控。。。。

最近发表
标签列表