JVM性能调优工具

03/10/2023

一、JDK工具

先来看看有哪些常用的工具可以辅助我们进行性能调优和问题排查,后面再通过一个具体的示例结合工具来分析调优。

1、JDK工具
JDK自带了很多性能监控工具,我们可以用这些工具来监测系统和排查内存性能问题。

2、利用 jps 找出进程
jps(Java Virtual Machine Process Status Tool)是JDK 1.5提供的一个显示当前所有java进程pid的命令,简单实用,非常适合在linux/unix平台上简单察看当前java进程的一些简单情况。

1)查看Java进程PID
【jps -l】左边一列就是Java进程的PID。

2)输出传递给JVM的参数
【jps -vl】

3、利用 jstat 查看VM统计信息
使用 jstat 工具可以监测 Java 应用程序的实时运行情况,可以看到VM内的Eden、Survivor、老年代的内存使用情况,还有 YoungGC 和 FullGC 的执行次数以及耗时。通过这些指标,我们可以轻松的分析出当前系统的运行情况,判断当前系统的内存使用压力以及GC压力,还有内存分配是否合理。

1)查看 jstat 有哪些操作
【jstat -options】
-class:显示 ClassLoad 的相关信息;
-compiler:显示 JIT 编译的相关信息;
-gc:显示和 gc 相关的堆信息;
-gccapacity:显示各个代的容量以及使用情况;
-gcmetacapacity:显示 Metaspace 的大小;
-gcnew:显示新生代信息;
-gcnewcapacity:显示新生代大小和使用情况;
-gcold:显示老年代和永久代的信息;
-gcoldcapacity :显示老年代的大小;
-gcutil:显示垃圾收集信息;
-gccause:显示垃圾回收的相关信息(同 -gcutil),同时显示最后一次或当前正在发生的垃圾回收的诱因;
-printcompilation:输出 JIT 编译的方法信息
其中 jstat -gc 是最完整、最常用、最实用的命令,基本足够分析jvm的运行情况了。

2)显示 ClassLoad 的相关信息
【jstat -class <pid>】

3)查看内存使用和GC情况
【jstat -gc <pid> [<interval> [<count>]】
S0C:年轻代中 To Survivor 的容量(单位 KB);
S1C:年轻代中 From Survivor 的容量(单位 KB);
S0U:年轻代中 To Survivor 目前已使用空间(单位 KB);
S1U:年轻代中 From Survivor 目前已使用空间(单位 KB);
EC:年轻代中 Eden 的容量(单位 KB);
EU:年轻代中 Eden 目前已使用空间(单位 KB);
OC:老年代的容量(单位 KB);
OU:老年代目前已使用空间(单位 KB);
MC:Metaspace 的容量(单位 KB);
MU:Metaspace 目前已使用空间(单位 KB);
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
YGC:从应用程序启动到采样时年轻代中 gc 次数;
YGCT:从应用程序启动到采样时年轻代中 gc 所用时间 (s);
FGC:从应用程序启动到采样时 old 代(全 gc)gc 次数;
FGCT:从应用程序启动到采样时 old 代(全 gc)gc 所用时间 (s);
GCT:从应用程序启动到采样时 gc 用的总时间 (s)

4)查看垃圾回收统计
【jstat -gcutil <pid> [<interval> [<count>]】
S0:Survivor0 区占用百分比
S1:Survivor1 区占用百分比
E:Eden 区占用百分比
O:老年代占用百分比
M:元数据区占用百分比
YGC:年轻代回收次数
YGCT:年轻代回收耗时
FGC:老年代回收次数
FGCT:老年代回收耗时
GCT:GC总耗时

4、利用 jmap 查看对象分布情况
使用 jmap 可查看堆内存初始化配置信息以及堆内存的使用情况,输出堆内存中的对象信息,包括产生了哪些对象,对象数量多少等。

1)查看堆内存情况
【jmap -heap <PID>】
这个命令会打印出堆内存相关的一些参数设置以及各个区域的情况,要查看这些信息一般使用 jstat 命令就足够了。

2)查看系统运行时对象分布
【jmap -histo[:live] <PID>】带上 live 则只统计活对象
这个命令会按照各种对象占用内存空间的大小降序排列,把占用内存最多的对象放在最上面。通过这个命令可以简单的了解下当前jvm中的对象对内存占用的情况以及当前内存里到底是哪个对象占用了大量的内存空间。

3)生成堆内存转储快照
【jmap -dump:format=b,file=<path> <pid>】
【jmap -dump:live,format=b,file=<path> <pid>】
jmap -dump 是输出堆中所有对象;jmap -dump:live 是输出堆中所有活着的对象,而且 jmap -dump:live 会触发 FullGC,线上使用要注意。format=b 是以二进制格式输出;file 是文件路径,格式为 hrpof 后缀。
这个命令会在当前目录下生成一个 dump.hrpof 文件,这是个二进制的格式,无法直接打开,可以使用MAT等工具来分析。这个命令把这一时刻VM堆内存里所有对象的快照放到文件里去了,供你后续去分析。

5、利用 jstack 分析线程栈
jstack 是一种线程堆栈分析工具,最常用的功能就是使用 jstack pid 命令查看线程的堆栈信息,通常会结合 top -Hp pid 或 pidstat -p pid -t 一起查看具体线程的状态,也经常用来排查一些死锁的异常、CPU占用高的线程等。

1)jstack参数
-l:长列表. 打印关于锁的附加信息,例如属于 java.util.concurrent 的 ownable synchronizers 列表。
-F:当 jstack [-l] pid 没有响应的时候强制打印栈信息
-m:打印 java 和 native c/c++ 框架的所有栈信息.
-h | -help:打印帮助信息

2)查看线程堆栈信息
【jstack <pid> > stack.log】
这个命令可以把程序的线程堆栈dump下来。每个线程堆栈的信息中,都可以查看到线程 ID、线程状态(wait、sleep、running 等状态)以及是否持有锁等。
pool-11-thread-6:线程名称
1920:线程编号
prio=5:线程的优先级别
os_prio=0:系统级别的线程优先级
tid=0x00007f87e028c000:线程ID
nid=0x6724:native线程的id,通过 printf “%x\n” 命令转换线程ID
waiting on condition [0x00007f87b97d2000]:线程当前的状态

二、Linux 命令行工具

1、top 命令
top 命令是我们在 Linux 下最常用的命令之一,它可以实时显示正在执行进程的 CPU 使用率、内存使用率以及系统负载等信息。其中上半部分显示的是系统的统计信息,下半部分显示的是进程的使用率统计信息。

2、vmstat 命令
vmstat 是 Virtual Meomory Statistics(虚拟内存统计)的缩写,可对操作系统的虚拟内存、进程、CPU活动进行监控。

命令格式:【vmstat [ 选项 ] [ <时间间隔> ] [ <次数> ]】

字段说明:

  • Procs(进程):
    • r:等待运行的进程数
    • b:处于非中断睡眠状态的进程数
  • Memory(内存,单位Kb):
    • swpd:虚拟内存使用情况
    • free:空闲的内存
    • buff:用来作为缓冲的内存数
    • cache:用作缓存的内存大小
  • Swap(交换区):
    • si:从磁盘交换到内存的交换页数量
    • so:从内存交换到磁盘的交换页数量
  • IO:(现在的Linux版本块的大小为1024bytes)
    • bi:发送到块设备的块数
    • bo:从块设备接收到的块数
  • System(系统):
    • in:每秒中断数,包括时钟中断。【interrupt】
    • cs:每秒上下文切换数。【count/second】
  • CPU(以百分比表示):
    • us:用户 CPU 使用时间(user time)
    • sy:内核 CPU 系统使用时间 (system time)
    • id:空闲时间(包括IO等待时间),中央处理器的空闲时间 。以百分比表示。
    • wa:等待IO时间

判断指标:

  • 如果 r 经常大于4,id 经常少于40,表示cpu的负荷很重。
  • 如果 bi,bo 长期不等于0,表示内存不足。
  • 如果 disk 经常不等于0,且在 b 中的队列大于3,表示io性能不好。
  • 通过 cs 观察 Java 程序运行过程中系统的上下文切换频率。过高说明程序创建了过多的线程导致频繁的上下文切换。

3、pidstat 命令

如果是监视某个应用的上下文切换,可以使用 pidstat 命令监控指定进程的上下文切换。pidstat 是 Sysstat 中的一个组件,也是一款功能强大的性能监测工具,我们可以通过命令:yum install sysstat 安装该监控组件。top 和 vmstat 两个命令都是监测进程的内存、CPU 以及 I/O 使用情况,而 pidstat 命令则是深入到线程级别。

命令格式:【**pidstat [ 选项 ] [ <时间间隔> ] [ <次数> ]】

1)常用的选项:

  • -u:默认的参数,显示各个进程的 cpu 使用情况
  • -r:显示各个进程的内存使用情况
  • -d:显示各个进程的 I/O 使用情况
  • -p:指定进程号
  • -w:显示每个进程的上下文切换情况
  • -t:显示进程中线程的统计信息
  • -T { TASK | CHILD | ALL }
    • TASK表示报告独立的task,CHILD关键字表示报告进程下所有线程统计信息。ALL表示报告独立的task和task下面的所有线程。
    • 注意:task和子线程的全局的统计信息和pidstat选项无关。这些统计信息不会对应到当前的统计间隔,这些统计信息只有在子线程kill或者完成的时候才会被收集。
  • -V:版本号
  • -h:在一行上显示了所有活动,这样其他程序可以容易解析。
  • -I:在SMP环境,表示任务的CPU使用率/内核数量
  • -l:显示命令名和所有参数

2)查看所有进程的 CPU 使用情况
命令格式:【pidstat】
命令格式:【pidstat -u -p ALL】

  • PID:进程ID
  • %usr:进程在用户空间占用cpu的百分比
  • %system:进程在内核空间占用cpu的百分比
  • %guest:进程在虚拟机占用cpu的百分比
  • %CPU:进程占用cpu的百分比
  • CPU:处理进程的cpu编号
  • Command:当前进程对应的命令

3)显示每个进程的上下文切换情况
命令格式:【pidstat -w -p <PID> <时间间隔>  <次数>】

  • PID:进程id
  • Cswch/s:每秒主动任务上下文切换数量
  • Nvcswch/s:每秒被动任务上下文切换数量
  • Command:命令名

4)显示进程中线程的统计信息
命令格式:【pidstat -p <PID> -t】