阅读 1167

JVM性能调优(5) —— 性能调优工具

系列文章专栏:JVM系列专栏

JDK工具

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

JDK工具

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

利用 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

利用 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、显示 ClassLoader 的相关信息

命令: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总耗时

利用 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堆内存里所有对象的快照放到文件里去了,供你后续去分析。

利用 jstack 分析线程栈

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

1、jstack参数

参数说明:

  • -l:长列表. 打印关于锁的附加信息,例如属于 java.util.concurrentownable 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" <pid> 命令转换线程ID
  • waiting on condition [0x00007f87b97d2000]:线程当前的状态

Linux 命令行工具

top 命令

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

看第一行:主要展示了CPU的负载情况

  • 23:22:23:指的是当前时间
  • up 12 days, 12:18:指的是机器已经运行了多长时间
  • 1 user:当前机器有一个用户在使用
  • load average: 0.19, 0.27, 0.30:指 CPU 在1分钟、5分钟、15分钟内的负载情况。

最重要的就是看 load average,比如机器是4核CPU,那么 0.19、0.27、0.30,说明4核中连一个核都没用满,4核CPU基本很空闲。如果CPU负载是1,说明有1个核被使用的比较繁忙了。如果负载是4,说明4核CPU都跑满了;如果超过4,说明4核CPU被繁忙的使用还不够处理当前的任务,很多进程可能一直在等待CPU去执行自己的任务。

查看具体线程使用系统资源情况

vmstat 命令

vmstatVirtual 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 程序运行过程中系统的上下文切换频率。过高说明程序创建了过多的线程导致频繁的上下文切换。

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 使用情况

命令:pidstatpidstat -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

可视化工具

下面简单介绍几款常用的可视化分析工具,一般我们需要将GC日志文件、堆转储文件dump下来,然后就可以通过这些工具来分析。如果是线上分析一般直接使用上面的那些JDK命令行工具就足够了,这些可视化工具可以做一些辅助性的分析。

jvisualvm — JVM监控

jvisualvm 是 jdk 提供的监控工具,位于 %JAVA_HOME%/bin/jvisualvm.exe,双击运行即可。

VisualVM 提供了一个可视界面,用于查看JVM上运行的基于 Java 技术的应用程序的详细信息。VisualVM 能够监控线程,内存情况,方法的CPU时间和内存中的对象,已被GC的对象,反向查看分配的堆栈(如100个String对象分别由哪几个对象分配出来的)等。

更详细的一些使用方式可以参考这篇文章:zhuanlan.zhihu.com/p/30837957

1、插件安装

VisualVM 基于NetBeans平台开发工具,它具备通过插件扩展功能的能力,有了插件扩展支持,VisualVM可以做到:

  • 显示虚拟机进程以及进程的配置、环境信息(jps、jinfo)
  • 监视应用程序的处理器、垃圾收集、堆、方法区以及线程的信息(jstat、jstack)
  • dump 以及分析堆转储快照(jmap、jhat)
  • 方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法
  • 离线程序快照:收集程序的运行时配置、线程dump、内存dump等信息建立一个快照,可以将快照发送开发者处进行Bug反馈
  • 其他插件带来的无限可能性

可以从工具选项中打开插件面板安装所需的插件:

2、监视面板

在左边选择需要监控的程序,右边就可以可查看CPU、堆、线程等波动情况,也可以直接在这里进行手动 GC 和堆 Dump 操作。

3、线程面板

可看到所有的线程,以及线程的运行状态。点击面板的线程 Dump 按钮,可以查看线程瞬时的线程栈。(通过 jstack 也可以抓取线程栈)

4、GC面板

可以很方便的看到GC趋势图。(也可使用 jstat 工具监控)

5、分析堆转储快照

通过左上角装入快照按钮打开 dump 的堆转储文件,就可以分析堆转储快照了。

GCViewer — 离线分析GC日志

GCViewer 可以离线查看GC日志,下载地址为 github.com/chewiebug/G… 。下载下来之后执行 [mvn clean install -Dmaven.test.skip=true] 命令打包编译,编译完成后在target目录下会看到jar包,然后在命令行运行这个jar包就可以启动 GCViewer。

然后通过 File 打开GC日志文件,就可以看到GC统计图和GC情况。通过工具,我们可以看到吞吐量、停顿时间以及 GC 的频率等信息,从而可以非常直观地了解到 GC 的性能情况。

GCeasy — 在线分析GC日志

GCeasy 是一款在线版的非常直观的 GC 日志分析工具,我们可以将日志文件压缩之后,上传到 GCeasy 官网即可看到非常清楚的 GC 日志分析结果。

FastThread — 分析线程栈

线程栈使用 jstack 命令 dump 下来后,可以使用 FastThread 在线工具分析线程栈信息,可以直观的看到有多少线程、线程池、线程的状态、是否有死锁等信息。

MAT — 分析堆转储文件

我们使用 jmap 命令 dump 下来的堆转储文件可以使用 MAT 来分析,可以分析创建了哪些对象,然后分析对象的引用链,找出问题所在。MAT 下载地址: www.eclipse.org/mat/downloa…

MAT 主要功能:

  • 找出内存泄漏的原因
  • 找出重复引用的类和jar
  • 分析集合的使用
  • 分析类加载器

性能调优工具

1、在线工具地址

线程 Dump 分析(FastThread): fastthread.io/

线程 Dump 分析(PerfMa): thread.console.perfma.com/

内存 Dump 分析(PerfMa): memory.console.perfma.com/

JVM 参数分析(PerfMa): opts.console.perfma.com/

GC 日志分析(GCEasy): www.gceasy.io/

GC 日志分析(GCViewer): github.com/chewiebug/G…

Java 诊断(Arthas): alibaba.github.io/arthas/

MAT: www.eclipse.org/mat/downloa…

2、调优工具选择

调优的工具很多,一般对于线上系统,使用 jstat 工具足以分析出JVM的运行情况,如果有GC日志,也可以使用 GCeasy 快速分析JVM的运行情况。

遇到CPU负载过高,可以使用 top + pidstat 找出负载高的线程,或者直接使用 jstat 观察是不是在频繁 FullGC。

遇到死锁、OOM 等问题,可以用 jstack 把线程栈dump下来分析,还可以结合 FastThread 在线工具,分析线程栈、哪些线程阻塞等待等。

遇到OOM问题,使用 jmap 把堆转储快照dump下来,用MAT来分析创建了哪些大量的对象。

JVM监控平台

系统上线后,如果不部署可视化的监控平台,我们一般就通过上面的这些工具来分析JVM的内存运转模型、GC情况等,可以在机器上运行jstat,让其把监控信息写入一个文件,每天定时检查—下。

监控平台则可以通过可视化的界面看到JVM各个区域的内存变化,GC次数和GC耗时等信息,以及出现性能问题时能及时报警。

一般可以部署 Zabbix、Ganglia、Open-Falcon、Prometheus 之类的可视化监控平台,把线上系统接入到这些平台,就可以直接图形化看到JVM的表现。

下一篇文章再详细解释使用工具来进行JVM性能调优

文章分类
后端
文章标签