零、背景说明
目前测试机器为 4C8G
两台机器完全处理一样的工作
大部分时间对象朝生夕死,很少进入老年代
CMS 指定了新生代最大 1536M,略微有点浪费
于是设置 G1 自动调节各个区域大小,看看能否有所改善
也因为最近重温了两本 JVM 相关的书籍,找机会进行实践看看
一、G1 设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| -Xms4096M -Xmx4096M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:SurvivorRatio=8 -XX:+ParallelRefProcEnabled -XX:MaxTenuringThreshold=6 -XX:ParGCCardsPerStrideChunk=4096 -XX:MaxGCPauseMillis=100 -XX:MaxMetaspaceSize=256M -XX:MetaspaceSize=256M -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:/home/hisen/gc.log
|
二、CMS 设置
最大最小设置成一致的值,是为了不让堆大小进行收缩(缩的过程会 GC)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| # 初始堆大小 -Xms4096M # 最大堆大小 -Xmx4096M # 年轻代的大小 -Xmn1536M # eden 区比例,此处为 8:1:1 -XX:SurvivorRatio=8 # 最大元空间大小 -XX:MaxMetaspaceSize=256M # 最小元空间大小 -XX:MetaspaceSize=256M # 使用 CMS 垃圾收集器 -XX:+UseConcMarkSweepGC # 只使用占用率作为启动 CMS GC 的标准,配合 CMSInitiatingOccupancyFraction 使用 -XX:+UseCMSInitiatingOccupancyOnly # CMS垃圾收集器,当老年代达一定比例,触发CMS垃圾回收。此处为 70% -XX:CMSInitiatingOccupancyFraction=70 # 默认为 false,并行的处理 Reference 对象,如 WeakReference,除非在 GC log 里出现 Reference 处理时间较长的日志,否则效果不会很明显。 -XX:+ParallelRefProcEnabled # 开启或关闭在CMS重新标记阶段之前的 YGC 尝试 -XX:+CMSScavengeBeforeRemark # 晋升老年代的阈值 -XX:MaxTenuringThreshold=6 # 解锁诊断参数,否则 ParGCCardsPerStrideChunk 不生效 -XX:+UnlockDiagnosticVMOptions # 每个线程扫描 old gen 的 CardTable (一定大小的内存块) 个数 -XX:ParGCCardsPerStrideChunk=4096 # 打印 GC 的时间戳 -XX:+PrintGCDateStamps # 打印 GC 明细日志 -XX:+PrintGCDetails # 存放 GC 日志的路径 -Xloggc:/home/hisen/gc.log
|
三、结果对比
Type | Duration | Xmn | YGC count | YGC avg | Interval Time |
---|
G1 | 72 hrs 21 min 8 sec | 1.66G | 7596 | 19.6 ms | 34 sec 294 ms |
CMS | 70 hrs 24 min 51 sec | 1.5G | 7029 | 14.4 ms | 36 sec 68 ms |
目前应用堆响应时间比较敏感,追求低延迟。
就上表来看,G1 新生代的大小确实上去了,但并不尽如人意。
但是随着而来的是 G1 『更频繁的YGC』以及『更长的停顿时间』
在《深入理解JVM虚拟机》第三版看到,
由于 G1 处理跨 region 需要耗费额外 10% ~ 20% 的资源,小堆 (堆大小<8G) 上没有优势。
JVM 新生代大小与老年代大小默认为 1:2,
大部分应用按这个设置是 OK 的,
虽然有时候看着老年代一直很小,
设置那么大浪费内存,但是当调用量大的时候,就能派上用场,减少 Full GC。
先占个坑,后续继续填内容。