JVM虚拟机系统性学习-JVM调优之通过gceasy分析GC日志对堆、元空间、线程堆栈和垃圾回收器进行调优

通过 gceasy工具对生成的 GC 日志进行分析

这里使用的 JDK 版本为 JDK8!

在分析 GC 日志时,可以同时采用多种工具(Arthas、gceasy、JVM 连接 Graphana 监控)进行分析,避免某种工具分析不准确

gceasy 每个月只可以免费分析 5 个 gc 日志,因此要节约机会!hhh!

我们先将 gc.log 文件放入 gceasy 中进行分析,分析结果如下:

首先是 JVM 内存大小,可以看到新生代分配了 624 mb,而 Peak 也就是峰值也达到了 624 mb,说明新生代很容易就被占满了,而对于元空间 Meta Space 来说,分配了 1 个 gb,而峰值才使用了 59 mb,因此元空间分配的大小也不合理,对于 JDK8 来说,如果不指定元空间的大小,默认元空间的最大值是系统内存的大小,在 64 位操作系统中,元空间默认初始值为 21MB,如果初始未给定的元空间的大小,导致初始元空间过小,会 频繁触发 Full GC 来调高元空间大小

接下来看一些关键的性能指标,可以看到 Avg Pause GC Time 也就是平均 GC 时间为 10 ms,最大 GC 时间为 190 ms,这些参数目前看来也正常,没有出现过长的 GC 时间

接下来看一下 GC 持续时间的一些情况,可以看到在系统刚开始就发生了几次 Full GC,这是很严重的问题,可以看到这三次 Full GC 产生的原因分别是:Metadata GC ThreasholdErgonomics,即元空间超过阈值,Ergonomics 的含义是自动调节 GC 暂停时间和吞吐量从而产生的 GC,是虚拟机中对性能的优化,那么因为 Ergonomics 产生的 GC 我们可以不管,总结一下这几次 Full GC 产生的原因就是 元空间超过阈值!

最后我们可以看一下 GC 的指标,可以看到 Full GC 总共发生了 6 次,还是比较多的,需要控制一下 Full GC 的次数,因为 Full GC 对系统性能影响是比较大的

上边我们已经通过 gceasy 分析了 gc 日志了,存在的问题主要有以下几点:

  • Meta Space 空间分配不合理
  • Full GC 产生次数过多
堆和元空间优化

那么优化参数我们从 堆空间元空间新生代 3 个方面进行入手,参数调整如下:

bash 复制代码
-Xms1096m -Xmx1096m -Xmn408m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m
  • 堆空间通过 -Xms -Xmx 来进行调整,为了尽量避免 Full GC,堆空间可以设置为 Full GC 后老年代空间占用的 3-4 倍 ,这样的话一般可以避免老年代空间不足从而导致 Full GC 的情况,最好设置为 8 的整数倍,我们通过上边 easygc 分析中的 JVM Memory Size 得知,老年代的峰值为 274mb,因此这里设置堆空间大小为 274 * 4 = 1096 mb,设置堆空间为 Full GC 后老年代对象的 4 倍大小
  • 元空间通过 -XX:MetaspaceSize=N 来设置,这里设置元空间大小为 128 mb
  • 新生代通过 -Xmn 来设置,新生代可以设置为 Full GC 后老年代空间占用的 1-1.5 倍 ,即 274 * 1.5 = 411 mb,最好设置为 8 的整数倍,因此改为 408 mb

可以看到优化后,JVM 内存的使用更加合理了,新生代也没有超过分配的内存大小,如下图:

并且 Full GC 的次数为 0

这里需要注意的是,如果使用 Docker 部署的 java 应用,可以在 Dockerfile 中设置 JVM 的参数,并且在启动的时候,尽量去将 JVM 参数打印出来,确保设置的参数生效!

线程堆栈优化

上边对 JVM 中的堆和方法区的大小进行了优化,接下来看一下如何对 JVM 中的线程堆栈进行优化

JDK5.0 后每个线程堆栈大小为 1M,在相同物理内存下,线程堆栈越小,就能生成更多的线程,但是操作系统对一个进程内的线程数量还是有限制的,如果堆栈不是很深可以设置 256k,如果是很大的应用可以使用 512k

对于平常的系统来说,是不需要进行线程堆栈的优化的,但是如果开发一些中间件的话,需要创建出很多的线程,那么对于线程堆栈的优化还是比较有必要的,线程堆栈大小设置通过 -Xss 进行设置

bash 复制代码
-Xms1096m -Xmx1096m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xss512k
垃圾回收器组合优化
  • 吞吐量优先:Parallel Scavenge + ParallelOldGC
  • 响应时间优先(低延迟):ParNew + CMS
G1 垃圾回收器

G1 兼顾了吞吐量和响应时间,尤其在大内存的情况下比较好,配置 G1 只需要 3 步:

  1. 开启 G1 垃圾收集器
  2. 设置堆内存
  3. 设置最大的停顿时间
bash 复制代码
 # 设置堆、元空间大小
 -Xms256m -Xmx256m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=128m -Xss512k
 # 开启 G1
 -XX:+UseG1GC -XX:MaxGCPauseMillis=100
  # 开启 GC 日志创建更详细的 GC 日志
 -XX:+PrintGCDetails -XX:+PrintGCTimeStamps,-XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -Xloggc:./logs/gc.log
相关推荐
m0_7482567825 分钟前
WebGIS实战开源项目:智慧机场三维可视化(学习笔记)
笔记·学习·开源
南七澄江2 小时前
各种网站(学习资源及其他)
开发语言·网络·python·深度学习·学习·机器学习·ai
机智的叉烧7 小时前
前沿重器[57] | sigir24:大模型推荐系统的文本ID对齐学习
人工智能·学习·机器学习
量子-Alex8 小时前
【多模态聚类】用于无标记视频自监督学习的多模态聚类网络
学习·音视频·聚类
吉大一菜鸡8 小时前
FPGA学习(基于小梅哥Xilinx FPGA)学习笔记
笔记·学习·fpga开发
东阳马生架构11 小时前
JVM简介—3.JVM的执行子系统
jvm
爱吃西瓜的小菜鸡11 小时前
【C语言】判断回文
c语言·学习·算法
小A15911 小时前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
岁岁岁平安12 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA12 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计