生产环境参数实例分析

生产环境参数实例分析

一、java application 项目(非 web 项目)

1.1、改进前

-Xms128m
-Xmx128m
-XX:NewSize=64m
-XX:PermSize=64m
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=78
-XX:ThreadStackSize=128
-Xloggc:logs/gc.log
-Dsun.rmi.dgc.server.gcInterval=3600000
-Dsun.rmi.dgc.client.gcInterval=3600000
-Dsun.rmi.server.exceptionTrace=true

问题:

  • permsize 设置较小,很容易达到报警范围 (0.8)。
  • 没有设置 MaxPermSize,堆增长会带来额外压力。
  • NewSize 较大,old gen 剩余空间 64m,一方面可能会带来 old 区容易增长到报警范围(监控数据显示 oldgenused 长期在 50m 左右,接近 78%,容易出现 full gc), 另一方面也存在 promontion fail 风险。

1.2、改进后

-Xms128m
-Xmx128m
-Xmn24m
-XX:PermSize=80m
-XX:MaxPermSize=80m
-Xss256k
-XX:SurvivorRatio=1
-XX:MaxTenuringThreshold=20
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSCompactAtFullCollection
-XX:+CMSParallelRemarkEnabled
-XX:CMSFullGCsBeforeCompaction=2
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:logs/gc.log
-Dsun.rmi.dgc.server.gcInterval=3600000
-Dsun.rmi.dgc.client.gcInterval=3600000
-Dsun.rmi.server.exceptionTrace=true

修改点:

  • PermSize 与 MaxPermSize 都设置为 80,一方面避免 non heap warn (报警阀值 0.8 非对内存一般占用到 60M 以内),一方面避免堆伸缩带来的压力
  • 通过设置 Xmn=24M 及 SurvivorRatio=1 使得 Eden 区 = from space=to space=8M, 降低了 Eden 区大小,降低 YGC 的时间 (降低到 3-4ms 左右), 同时通过设 MaxTenuringThreshold=20,使得 old gen 的增长很缓慢。带来的问题是 YGC 的次数明显提高了很多。
  • 其他参数优化 修改后带来的好处见 JVM 参数设置。

1.3、再次改进

-Xms128m
-Xmx128m
-Xmn36m
-XX:PermSize=80m
-XX:MaxPermSize=80m
-Xss256k
-XX:SurvivorRatio=1
-XX:MaxTenuringThreshold=20
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=73
-XX:+UseCMSCompactAtFullCollection
-XX:+CMSParallelRemarkEnabled
-XX:CMSFullGCsBeforeCompaction=2
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:logs/gc.log
-Dsun.rmi.dgc.server.gcInterval=3600000
-Dsun.rmi.dgc.client.gcInterval=3600000
-Dsun.rmi.server.exceptionTrace=true

修改点:
在上面的基础上调整 Xmn 大小到 36M,设置 CMSInitiatingOccupancyFraction=73。
Dden 区与 Survivor 区大小都增加到 12M,通过 CMSInitiatingOccupancyFraction 计算公式,计算得出 value 为 73 是,可以避免 promotion faild 问题,同时满足堆内存监控报警值在 80%:内存大小 128M80%=102.4M 102.4M-36M=66.4M (老生代达到此值报警) 老生代达到 67.15M(92M0.73)将发生 Full GC,所以在老生代大小达到 66.4M 时也就是 WARN 报警时将很有可能出现 Full GC。
增大了 Eden 和 Survivor 区的值,会减小 YGC 的次数,但由于空间变大理论上也会相应的增加 YGC 的时间,不过由于新生代本身就很小(才 36M)这点儿变化可以忽略掉。实际的监控值显示 YGC 的时间在 4-5ms 之间。是可以接受范围。
SurvivorRatio 这个值还得在仔细考虑下,有待优化中。

二、示例

$JAVA_ARGS
.=
"
-Dresin.home=$SERVER_ROOT
-server
-Xms6000M
-Xmx6000M
-Xmn500M
-XX:PermSize=500M
-XX:MaxPermSize=500M
-XX:SurvivorRatio=65536
-XX:MaxTenuringThreshold=0
-Xnoclassgc
-XX:+DisableExplicitGC
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSClassUnloadingEnabled
-XX:-CMSParallelRemarkEnabled
-XX:CMSInitiatingOccupancyFraction=90
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:log/gc.log
";

说明一下, -XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0 就是去掉了救助空间;
-Xnoclassgc 禁用类垃圾回收,性能会高一点;
-XX:+DisableExplicitGC 禁止 System.gc (),免得程序员误调用 gc 方法影响性能;
-XX:+UseParNewGC,对年轻代采用多线程并行回收,这样收得快;
带 CMS 参数的都是和并发回收相关的,不明白的可以上网搜索;
CMSInitiatingOccupancyFraction,这个参数设置有很大技巧,基本上满足 (Xmx-Xmn)(100-CMSInitiatingOccupancyFraction)/100>=Xmn 就不会出现 promotion failed。在我的应用中 Xmx 是 6000,Xmn 是 500,那么 Xmx-Xmn 是 5500 兆,也就是年老代有 5500 兆,CMSInitiatingOccupancyFraction=90 说明年老代到 90% 满的时候开始执行对年老代的并发垃圾回收(CMS),这时还剩 10% 的空间是 550010%=550 兆,所以即使 Xmn(也就是年轻代共 500 兆)里所有对象都搬到年老代里,550 兆的空间也足够了,所以只要满足上面的公式,就不会出现垃圾回收时的 promotion failed;
SoftRefLRUPolicyMSPerMB 这个参数我认为可能有点用,官方解释是 softly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap,我觉得没必要等 1 秒;

-Xmx4000M
-Xms4000M
-Xmn600M
-XX:PermSize=500M
-XX:MaxPermSize=500M
-Xss256K
-XX:+DisableExplicitGC
-XX:SurvivorRatio=1
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSClassUnloadingEnabled
-XX:LargePageSizeInBytes=128M
-XX:+UseFastAccessorMethods
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=80
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:log/gc.log

改进方案:
上面方法不太好,因为没有用到救助空间,所以年老代容易满,CMS 执行会比较频繁。我改善了一下,还是用救助空间,但是把救助空间加大,这样也不会有 promotion failed。
具体操作上,32 位 Linux 和 64 位 Linux 好像不一样,64 位系统似乎只要配置 MaxTenuringThreshold 参数,CMS 还是有暂停。为了解决暂停问题和 promotion failed 问题,最后我设置 - XX:SurvivorRatio=1 ,并把 MaxTenuringThreshold 去掉,这样即没有暂停又不会有 promotoin failed,而且更重要的是,年老代和永久代上升非常慢(因为好多对象到不了年老代就被回收了),所以 CMS 执行频率非常低,好几个小时才执行一次,这样,服务器都不用重启了。

参考示例:

$JAVA_ARGS
.=
"
-Dresin.home=$SERVER_ROOT
-server
-Xmx3000M
-Xms3000M
-Xmn600M
-XX:PermSize=500M
-XX:MaxPermSize=500M
-Xss256K
-XX:+DisableExplicitGC
-XX:SurvivorRatio=1
-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-XX:+CMSParallelRemarkEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:CMSFullGCsBeforeCompaction=0
-XX:+CMSClassUnloadingEnabled
-XX:LargePageSizeInBytes=128M
-XX:+UseFastAccessorMethods
-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=70
-XX:SoftRefLRUPolicyMSPerMB=0
-XX:+PrintClassHistogram
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-Xloggc:log/gc.log
";

64 位 jdk 参考设置,年老代涨得很慢,CMS 执行频率变小,CMS 没有停滞,也不会有 promotion failed 问题,内存回收得很干净。

评论

暂无

添加新评论