结合压测反馈进行JVM调优

结合压测反馈进行JVM调优


分析

JVM参数

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
35
36
37
38
39
40
# 【CMS相关】:
# 开启CMS
-XX:+UseConcMarkSweepGC
# 默认CMS不收集永久代,用此参数可以对永久代进行并行垃圾收集
-XX:-CMSClassUnloadingEnabled
# 并行标记,降低标记停顿
-XX:+CMSParallelRemarkEnabled
# =====================================================
# 【堆相关】:
# -Xms
-XX:InitialHeapSize=4294967296
# -Xmx = -Xms,可以防止自动扩容
-XX:MaxHeapSize=4294967296
# 新生代:
# 新生代最大大小
-XX:MaxNewSize=1610612736
# -Xmn
-XX:NewSize=1610612736
# 新生代对象最大年龄
-XX:MaxTenuringThreshold=6
# 新生代并行收集
-XX:+UseParNewGC
# =====================================================
# 【64位架构相关】:
# 压缩类指针
-XX:+UseCompressedClassPointers
# 压缩对象指针
-XX:+UseCompressedOops
# =====================================================
# 【日志相关】:
-XX:GCLogFileSize=20971520
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/opt/wildfly/standalone/log/
-XX:NumberOfGCLogFiles=10
-XX:+PrintGC
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintHeapAtGC
-XX:+UseGCLogFileRotation

JDK版本:1.8 64位

JDK8中MetaSpace取代了PermGen,同时G1收集器已存在,同时由于是64位系统,所以可以分配的堆空间理论上是无限的,且由于指针膨胀、数据类型对齐补白等因素,64位系统上GC普遍比32位慢,但是可以看到参数中通过-XX:+UseCompressedClassPointers-XX:+UseCompressedOops进行了压缩
但是没有JDK11出现的ZGC,以及JDK12对G1做出的2种优化:

  1. 设置预期停顿时间,如果超过此时间可以自动停止GC
  2. 将回收后的内存自动返还给系统
1
2
3
java.runtime.name = OpenJDK Runtime Environment
java.runtime.version = 1.8.0_92
sun.arch.data.model = 64

结合后续的参数可以看到并没有开启G1开启G1可以更好地适用多核多CPU、大内存的环境,可以预测停顿时间

堆内存

堆已用内存
年轻代
老年代

  1. 元空间分配了1.08G,峰值只使用了97MB,说明元空间压力不大,可以适当缩小。

  2. 年轻代1.5G,峰值1.3G,没有什么参考价值,因为young gc速度比较快,代价较小。

  3. 老年代2.5G,峰值达到了2.3G,势必会出现full gc,应该要减少到达老年代的对象,让GC尽可能在年轻代进行,减少full gc的频率

    结合后续的参数可以看到-XX:MaxTenuringThreshold=6,对象移入老年代的年龄比较小,应该要适当提高。

  4. 总的堆大小5G,对于除G1ZGC外的收集器来说,堆越大则GC停顿时间越长,可以提高JDK版本以启用G1ZGC,在1T的堆内存上可以做到10ms的停顿时间

吞吐量 & GC停顿时间

吞吐量&停顿时间

平均GC停顿时间14.5ms,但是最高停顿时间达到了620ms,应该是full gc造成的。

收集器:ParNew & CMS

  1. 新生代采用的ParNew
  2. 此外还采用了CMS,通过-XX:+CMSParallelRemarkEnabled开启了并行标记,但是没有通过-XX:CMSFullGCsBeforeCompaction-XX:+UseCMSCompactAtFullCollection对内存进行压缩和整理,存在的内存碎片会提前导致full gc
    CMS

GC成因

GC原因

  1. 年轻代内存不足造成的young gc占绝大多数,可以提高年轻代比例
  2. MetaSpace的GC发生了8次每次都是full gc,应该考虑加大MetaSpace,并且减少代码中的反射调用

优化

  1. 开启G1,使用并行+并发GC的模式,追求可控制的停顿时间。如果有可能的话,使用JDK12,G1可以在时间超过阈值时自动停止GC,并且GC回收的内存会主动归还给OS
  2. 如果有可能的话,使用ZGC,可以达到在1T堆内存上毫秒级别的停顿时间
  3. CMS对CPU性能有影响,并且依赖CPU,会造成恶性循环,可以考虑替换为G1ZGC,同时CMS存在内存碎片,应该要开启内存整理和压缩
  4. 调整年轻代年龄阈值,扩大年轻代,缩小老年代,争取对象回收都采用young gc,尽可能避免full gc
  5. 在当前情况下,堆的总大小不改变,因为堆越大,GC的频率减少但是每次的耗时增加,另一方面,堆越大就会挤压到其他部分的内存,MetaSpace就会缩小,同时OS本地内存也受到挤压,可以分配的线程数就降低。如果使用ZGC就没有这方面的烦恼
  6. MetaSpace内存不足造成的full gc频繁出现,应该要考虑扩张MetaSpace,并且要警惕代码中的反射调用
-------------本文结束感谢您的阅读-------------

本文标题:结合压测反馈进行JVM调优

文章作者:DragonBaby308

发布时间:2019年08月06日 - 22:31

最后更新:2019年12月02日 - 23:01

原始链接:http://www.dragonbaby308.com/gceasy/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

急事可以使用右下角的DaoVoice,我绑定了微信会立即回复,否则还是推荐Valine留言喔( ఠൠఠ )ノ
0%