改变世界的是这样一群人,他们寻找梦想中的乐园,当他们找不到时,他们亲手创造了它

JVM调优工具和GC日志

一、JDK自带调优工具jvisualvm

1、启动jvisualvm,打开cmd,输入jvisualvm就会打开jvisualvm工具

启动好是这样的。左侧可以看到本地Test类在运行

双击打开可以看到JVM基本参数设置和运行环境

安装Visual GC插件,打开工具》插件,点击编辑

打开VisualVM网站地址VisualVM: Home

点击Plugins Offlin,选择与自己JDK版本对应的工具

复制插件链接地址

在此处粘贴,点击确定

点击可用插件》点击安装》点击下一步》完成

点击左侧VisualVM》Visual GC,可以看到内存分布情况。整个区域总体分为三部分:

 

  • spaces:代表虚拟机内存分布情况,虚拟机被分为Metaspace(元空间)、 Old、Eden、S0、S1
  • graphs:内存使用详细介绍
Compile Time(编译时间):10638 compiles 表示编译总数,23.732s表示编译累计 时间。一个脉冲表示一次JIT编译,窄脉冲表示持续时间短,宽脉冲表示持续时间长。
Class Loader Time(类加载时间): 8214 loaded表示加载类数量, 41 unloaded 表示卸载的类数量,7.858s表示类加载花费的时间
GC Time(GC Time):39 collections表示垃圾收集的总次数,475.316s表示垃圾 收集花费的时间,last cause表示最近垃圾收集的原因
Eden Space(Eden 区):(84.500M表示最大容量,29.000M表示当前容量),8.134M表示当前使用情况,36 collections表示垃圾收集次数,269.053ms表示垃 圾收集花费时间
Survivor 0/Survivor 1(S0和S1区):(28.000M表示最大容量,27.500M表示当前容量),之后的值是20.521M是当前使用情况
Old Gen(老年代):(171.000M表示最大容量,55.000M表示当前容量), 32.225表示当前使用情况,3 collections表示垃圾收集次数 ,206.262ms表示垃圾收集花费时间
Metaspace(元空间):(1.0459.000M表示最大容量,53.289M表示当前容量),50.248M表示当前使用情
    • histogramspaces区域:survivor区域参数跟年龄柱状图

二、阿里调优工具Arthas

1、操作系统环境

CentOS Linux release 7.9.2009 64位

2、安装Arthas

官网地址:Arthas,使用如下指令下载arthas-boot.jar包

curl -O https://arthas.aliyun.com/arthas-boot.jar 

3、开始使用

在使用Arthas工具前,确保JDK的环境变量是OK的!!!

启动指令:java -jar arthas-boot.jar

第一个红色箭头是启动调优工具Arthas,第二个箭头上一行显示* [1] 11141 Arthas,表示有个Arthas程序在运行,进程号是11141。这是自己编写的代码,类名是Arthas,不要弄混了哟!!!假如有多个程序会列出多个。

1)、输入1表示查看该进程信息,使用dashborad命令可以查看整个进程的运行情况,线程、内存、GC、运行环境信息。会定时刷新。第一部分显示哪个进程占用CPU最高,第二部分显示内存堆eden区、老年代使用情况,第三部分显示程序运行时环境。

2)、使用thread查看程序线程详情

3)、使用thread [pid]查看线程堆栈,如下显示哪一行代码一直占用内存。

4)、使用thread -b查看死锁

5)、使用thread [pid]查看线程堆栈

6)、使用jad Arthas反编译.class文件

7)、查看某个类的成员变量,

ognl @Arthas@hashSet //如果类在编译时加了包名,这里就要写全包名。因为我在编译时把包名注释掉了,所以这里就不用写包名了

8)、动态修改线上代码

ognl '@Arthas@hashSet.add("我是baby")'

9)、退出Arthas

如果只是退出当前的连接,可以用quit或者exit命令。Attach 到目标进程上的 arthas 还会继续运行,端口会保持开放,下次连接时可以直接连接上。如果想完全退出 arthas,可以执行stop命令。

以上只介绍了一些常用指令,更多进阶功能请查看Arthas官方文档。

三、GC日志

1、GC日志打印输出到文件

在java里我们可以通过一些配置将程序运行时的GC日志全部打印出来,然后通过专业的工具进行日志分析,分析GC日志,调优JVM参数。

首先在JVM参数配置GC日志参数:

-Xloggc:./gc-%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M 
各参数含义:
-Xloggc:./gc-%t.log:指定GC日志文件的名称和位置。%t是一个占位符,将被替换为当前的毫秒级时间。./表示当前目录,文件名以"gc-"开头。

-XX:+PrintGCDetails:启用打印每个GC事件的详细信息,包括GC前后的堆大小、GC的持续时间以及GC的原因。

-XX:+PrintGCDateStamps:启用打印每个GC事件的时间戳。

-XX:+PrintGCTimeStamps:启用打印每个GC事件距离JVM启动的经过时间。

-XX:+PrintGCCause:启用打印每个GC事件的原因,例如通过System.gc()调用触发的全GC,或者通过分配失败触发的并发GC。

-XX:+UseGCLogFileRotation:启用日志文件的轮转,当日志文件达到指定的大小限制时,将关闭该文件并创建一个新的日志文件。这样可以确保GC日志不会占用过多的磁盘空间。

-XX:NumberOfGCLogFiles=10:设置要保留的GC日志文件的最大数量。当达到最大数量时,最旧的日志文件将被删除。

-XX:GCLogFileSize=100M:设置每个GC日志文件的大小。当文件达到此大小时,将关闭该文件并创建一个新的日志文件。该值以兆字节(M)为单位指定。

接着我们结合以上参数启动应用程序

java -jar -Xloggc:./gc-%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M test-server.jar 

项目启动成功后,看到一个GC的文件:gc-2023-05-12_09-31-01.log.0.current

2、GC日志文件输出内容的含义

打开GC日志文件可以看到GC回收信息,例如Full GC

我们摘取其中一条来说一下各个含义:

2023-05-12T09:31:02.051+0800: 0.657: [Full GC (Metadata GC Threshold) [PSYoungGen: 6973K->0K(418816K)] [ParOldGen: 104K->6713K(267776K)] 7077K->6713K(686592K), [Metaspace: 20825K->20825K(1069056K)], 0.0140138 secs] [Times: user=0.08 sys=0.03, real=0.01 secs]

2023-05-12T09:31:02.051+0800: //发生Full gc的日期时间
0.657 //JVM启动开始计算到本次触发Full gc经过的时间
[Full GC (Metadata GC Threshold) // 发生Full gc的原因
[PSYoungGen: 6973K->0K(418816K)] //年轻代,6973是触发Full gc之前的年轻代大小,0发生后大小,418816年轻代总大小
[ParOldGen: 104K->6713K(267776K)] //老年代,含义同PSYoungGen
7077K->6713K(686592K) //
[Metaspace: 20825K->20825K(1069056K)] //元空间,
0.0140138 secs] // 该时间点GC总耗时
[Times: user=0.08 sys=0.03, real=0.01 secs] //GC事件的时间统计信息。user 表示用户态的CPU时间,sys 表示内核态的CPU时间,real 表示实际经过的时间。

很明显Full gc回收的原因是因为元空间不够导致,那么针对这个原因,我们可以把元空间设置大一些,例如:

java -jar -Xloggc:./gc-%t.log -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M test-server.jar 

先停掉应用程序,删除原来gc日志文件,使用上面的启动参数重新启动一下,发现没有Full gc了。

3、CMS、G1的GC日志

我们上面说明了JVM默认ParallelGC日志文件格式及内容的含义,在JVM里面还有其他的GC垃圾收集器,例如CMS、G1,这两款垃圾收集器的GC日志文件与ParallelGC大同小异。

使用CMS垃圾收集器,在参数的最后增加-XX:+UseParNewGC -XX:+UseConcMarkSweepGC

java -jar -Xloggc:./gc-%t.log -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC test-server.jar

查看日志内容:

使用G1垃圾收集器,在参数的最后增加-XX:+UseG1GC

java -jar -Xloggc:./gc-%t.log -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UseG1GC test-server.jar 

查看日志内容:

四、GC日志分析工具

在实际的开发中和项目上线后,我们通过肉眼去查看分析GC日志是一件很难且耗时的事,面对巨多的日志文件用眼睛去看,根本就不合适!!!推荐使用专业的工具去分析,例如:gceasy.io,进入官网是这样的

具体使用教程如下:

我们打印GC日志文件后,将GC的日志文件上传的到该网站,它会自动分析,给出分析报告及优化建议(收费的)

点击Analyze,提示分析中,请稍等

结果出来了,JVM内存大小信息,显示年轻代、老年代、元空间等信息

GC停顿时长

堆内存在GC之前和之后的变化

因为收费,如果要查看优化建议需要成为会员。

这里提供2款还不错且免费的GC分析工具:

1.GCViewer

GitHub - chewiebug/GCViewer: Fork of tagtraum industries' GCViewer. Tagtraum stopped development in 2008, I aim to improve support for Sun's / Oracle's java 1.6+ garbage collector logs (including G1 collector)

2.gctoolkit

GitHub - microsoft/gctoolkit: Tool for parsing GC logs

最后别忘了JDK自带工具VisualVM,也可以导入日志文件哟!!!

posted @ 2023-10-12 11:03  水狼一族  阅读(240)  评论(0编辑  收藏  举报
改变世界的是这样一群人,他们寻找梦想中的乐园,当他们找不到时,他们亲手创造了它