性能监控工具

性能是任何一款软件都需要关注的重要指标。除了软件的基本功
能,性能可以说是评价软件优劣的最重要的指标之一。我们该如何有
效地监控和诊断性能问题呢?本章基于实践,着重介绍一些针对系统
和Java虚拟机的监控和诊断工具,以帮助读者在实际开发过程中改善
系统性能。
本章涉及的主要知识点有:
· Linux下的性能监控工具。
· Windows下的性能监控工具。
· JDK自带的命令行工具。
· JConsole、Visual VM和Mission Control的介绍。

Linux下的性能监控工具

top命令----显示系统整体资源使用情况

top命令是Linux常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况。top命令的部分输出如下:
在这里插入图片描述
top命令的输出可以分为两个部分:前半部分是统计信息,后半部分是进程信息。

在统计信息中,
第1行是任务队列信息,它的结果等同于uptime命令。从左到右依次表示系统当前时间、系统运行时间、当前登录用户数。最后的load average表示系统的平均负载,即任务队列的平均长度,其中的3个值分别表示1分钟、5分钟、15分钟到现在的平均值。
第2行是进程统计信息,分别是正在运行的进程数、睡眠进程数、停止的进程数、僵尸进程数。
等3行是CPU统计信息,us表示用户空间CPU占用率、sy表示内核空间CPU占用率、ni表示用户进程空间改变过优先级的进程CPU的占用率、id表示空闲CPU占用率、wa表示等待输入和输出的CPU时间百分比、hi表示硬件中断请求、si表示软件中断请求。
在Mem中,从左到右,依次表示物理内存总量、已使用的物理内存、空闲物理内
存、内核缓冲使用量。
在Swap中,依次表示交换区总量、空闲交换区大小、缓冲交换区大小。

top命令的第2部分是进程信息,显示了系统内各个进程的资源使
用情况,主要字段的含义如下。
· PID:进程ID。
· USER:进程所有者的用户名。
· PR:优先级。
· NI:nice值,负值表示高优先级,正值表示低优先级。
·%CPU:上次更新到现在的CPU时间占用百分比。
· TIME+:进程使用的CPU时间总计,单位为1/100秒。
·%MEM:进程使用的物理内存百分比。
·
VIRT:进程使用的虚拟内存总量,单位为KB,VIRT=SWAP
+RES。
·
RES:进程使用的、未被换出的物理内存大小,单位为KB,
RES=CODE+DATA。
· SHR:共享内存大小,单位为KB。
· COMMAND:命令名/命令行。

注意: 使用top命令可以从宏观上观察系统中各个进程的CPU占
用情况,以及内存使用情况。

vmstat命令-----监控内存和CPU

vmstat命令也是一个功能比较齐全的性能监测工具。它可以统计CPU、内存使用情况、Swap使用情况等信息。和sar工具类似,vmstat也可以指定采样周期和采样次数。

示例6-1】下例每秒采样一次,共计3次。
在这里插入图片描述
输出结果中各列含义如表6.1所示。

表6.1 vmstat命令输出结果中各列含义
在这里插入图片描述
以下代码显示了一个线程切换频繁的Java程序。
在这里插入图片描述
在这里插入图片描述
使用vmstat工具监控上述Java程序执行时的情况
在这里插入图片描述
可以看到,加粗部分有着很高的cs值(上下文切换)和us值(用户CPU时间),表明系统的上下文切换频繁,用户CPU占用率很高。注意: vmstat工具可以查看内存、交互分区、I/O操作、上下文切换、时钟中断及CPU的使用情况。

iostat命令—监控I/O

iostat命令可以提供详细的I/O信息,它的基本使用方法如下
在这里插入图片描述
在这里插入图片描述

以上命令显示了CPU的使用概况和磁盘I/O的信息。输出信息每1秒采样1次,合计采样两次。如果只需要显示磁盘情况,不需要显示CPU使用情况,则可以使用命令:
在这里插入图片描述
-d表示输出磁盘使用情况。输出结果中各列的含义如下。
· tps:该设备每秒的传输次数。
· kB_read/s:每秒从设备读取的数据量。
· kB_wrtn/s:每秒向设备写入的数据量。
· kB_read:读取的总数据量。
· kB_wrtn:写入的总数据量。
如果需要得到更多的统计信息,可以使用-x选项,如:
在这里插入图片描述
注意:
磁盘I/O很容易成为系统性能瓶颈,通过iostat命令可以快速定位系统是否产生了大量的I/O操作。

pidstat工具----多功能诊断器

pidstat是一个功能强大的性能监测工具,也是Sysstat的组件之一。读者可以在http://www.icewalkers.com/Linux/Software/59040/Sysstat.html下载这个工具。下载后,通过./configure、make、make install等3个命令即可安装pidstat工具。如
果是Ubuntu系统,也可以简单地通过以下命令安装:
在这里插入图片描述
pidstat工具的强大之处在于,它不仅可以监视进程的性能情况,也可以监视线程的性能情况。本节将详细介绍pidstat在这方面的功能。

1.CPU使用率监控

【示例6-3】下例是一个简单地占用CPU的程序,它开启了4个用户线程,其中,1个线程大量占用CPU资源,其他3个线程则处于空闲状态。
在这里插入图片描述
运行以上程序,要监控该程序的CPU使用率,可以先使用jps命令找到Java程序的PID,然后使用pidstat命令输出程序的CPU使用情况。
在这里插入图片描述
在这里插入图片描述

pidstat的参数-p用于指定进程ID,-u表示对CPU使用率的监控。参数1 3表示每秒采样一次,合计采样3次。从这个输出中可以看到,该应用程序CPU占用率几乎达100%。pidstat的功能不仅仅限于观察进程信息,还可以进一步监控线程的信息。使用以下命令:
在这里插入图片描述
这个命令的部分输出如下
在这里插入图片描述
-t参数将系统性能的监控细化到线程级别。从这个输出中可以知道,该Java应用程序之所以有如此高的CPU占用率,是因为线程1204的缘故。

注意: 使用pidstat工具不仅可以定位到进程,甚至可以进一步定位到线程。 使用以下命令可以导出指定Java应用程序的所有线程:在这里插入图片描述
在输出的t.txt文件中,可以找到这么一段输出内容:
在这里插入图片描述
从加粗的部分可以看到,这个线程正是HoldCPUTask类,它的nid(native ID)为0x4b4,转为10进制后,正好是1204。通过这个方法,开发人员可以很容易地捕获在Java应用程序中大量占用CPU的线程。

2.I/O使用情况监控

磁盘I/O也是常见的性能瓶颈之一,使用pidstat工具也可以监控进程内线程的I/O情况。
【示例6-4】下例开启了4个线程,其中线程HoldIOTask产生了大量的I/O操作。
在这里插入图片描述
在程序运行过程中,使用以下命令监控程序I/O使用情况。其中22796是通过jps命令查询得到的进程ID,-d参数表明监控对象为磁盘I/O。1 3表示每秒采样一次,合计采样3次。
在这里插入图片描述
从输出结果中可以看到,进程中的22813(0x591D)线程产生I/O操作。通过前文中提到的jstatck命令,可以导出当前线程堆栈,查找nid为22813(0x591D)的线程,即可定位到HoldIOTask线程。
注意: 使用pidstat可以查看进程和线程的I/O信息。

3.内存监控

使用pidstat工具,还可以监控指定进程的内存使用情况。
【示例6-5】下例使用pidstat工具对进程ID为27233的进程进行
内存监控。每秒刷新一次,共进行5次统计。
在这里插入图片描述
在这里插入图片描述
输出结果中各列含义如下。
· minflt/s:表示该进程每秒minor faults (不需要从磁盘中调出
内存页)的总数。
· majflt/s:表示该进程每秒major faults(需要从磁盘中调出内
存页)的总数。
· VSZ:表示该进程使用的虚拟内存大小,单位为KB。
· RSS:表示该进程占用的物理内存大小,单位为KB。
·%MEM:表示占用内存比例。
注意:
pidstat工具是一款多合一的优秀工具。它不仅可以监控
CPU、I/O和内存资源,甚至可以将问题定位到相关线程,方便对应
用程序进行故障排查。

JDK性能监控工具

在这里插入图片描述
图6.16 JDK内置工具
在这里插入图片描述

jps命令 ----查看Java进程

jps命令类似于Linux下的ps命令,但它只用于列出Java的进程。直接运行jps命令不加任何参数,可以列出Java程序进程ID及Main函数名称,如下所示:
在这里插入图片描述
从这个输出中可以看到,当前系统中共存在3个Java应用程序,其中第一个输出Jps就是jps命令本身,这更加证明此命令的本质也是一个Java程序。此外,jps命令还提供了一系列参数来控制它的输出内容。
参数-q可以指定jps只输出进程ID,而不输出类的名称:
在这里插入图片描述
参数-m可以用于输出传递给Java进程(主函数)的参数:
在这里插入图片描述
参数-l可以用于输出主函数的完整路径:
在这里插入图片描述

参数-l可以用于输出主函数的完整路径:
在这里插入图片描述
参数-v可以显示传递给Java虚拟机的参数:
在这里插入图片描述
注意: jps命令类似于ps命令,但是它只列出系统中所有的Java应用程序。通过jps命令可以方便地查看Java进程的启动类、传入参数和Java虚拟机参数等信息。

jstat命令----查看虚拟机运行时信息

jstat命令是一个可以用于观察Java应用程序运行时相关信息的工具。它的功能非常强大,可以通过它查看堆信息的详细情况。它的基本使用语法为:
在这里插入图片描述
· option可以由以下值构成。
○-class:显示ClassLoader的相关信息。
○-compiler:显示JIT编译的相关信息。
○-gc:显示与GC相关的堆信息。
○-gccapacity:显示各个代的容量及使用情况。
○-gccause:显示垃圾回收相关信息(同-gcutil),同时显示最后一次或当前正在发生的垃圾回收的诱发原因。
○-gcnew:显示新生代信息。
○-gcnewcapacity:显示新生代大小与使用情况。
○-gcold:显示老年代和永久代的信息。
○-gcoldcapacity:显示老年代的大小。
○-gcpermcapacity:显示永久代的大小。
○-gcutil:显示垃圾回收信息。
○-printcompilation:输出JIT编译的方法信息。
·-t参数可以在输出信息前加上一个Timestamp列,显示程序的运行时间。
·-h参数可以指定在周期性数据输出时,输出多少行数据后输出一个表头信息。
· interval参数用于指定输出统计数据的周期,单位为毫秒。
· count参数用于指定一共输出多少次数据。如下示例输出Java进程2972的ClassLoader相关信息。每秒统计一次信息,一共输出两次。
在这里插入图片描述
在-class的输出中,Loaded表示载入类的数量,Bytes表示载入类的合计大小,Unloaded表示卸载类的数量,第2个Bytes表示卸载类的大小,Time表示在加载和卸载类上所花的时间。下例显示了查看JIT编译的信息:
在这里插入图片描述
Compiled表示编译任务执行的次数,Failed表示编译失败的次数,Invalid表示编译不可用的次数,Time表示编译的总耗时,FailedType表示最后一次编译失败的类型,FailedMethod表示最后一次编译失败的类名和方法名。
下例显示了与GC相关的堆信息的输出:
在这里插入图片描述
· S0C:s0(from区)的大小(KB)。
· S1C:s1(from区)的大小(KB)。
· S0U:s0(from区)已使用的空间(KB)。
· S1U:s1(from区)已使用的空间(KB)。
· EC:eden区的大小(KB)。
· EU:eden区的使用空间(KB)。
· OC:老年代大小(KB)。
· OU:老年代已经使用的空间(KB)。
· PC:永久区大小(KB)。
· PU:永久区的使用空间(KB)。
· YGC:新生代GC次数。
· YGCT:新生代GC耗时。
· FGC:Full GC次数。
· FGCT:Full GC耗时。
· GCT:GC总耗时。

下例显示了各个代的信息,与-gc相比,它不仅输出了各个代的当前大小,也包含了各个代的最大值和最小值。
在这里插入图片描述
· NGCMN:新生代最小值(KB)。
· NGCMX:新生代最大值(KB)。
· NGC:当前新生代大小(KB)。
· OGCMN:老年代最小值(KB)。
· OGCMX:老年代最大值(KB)。
· PGCMN:永久代最小值(KB)。
· PGCMX:永久代最大值(KB)。
下例显示了最近一次GC的原因,以及当前GC的原因:
在这里插入图片描述
· LGCC:上次GC的原因。
· GCC:当前GC的原因。
本例显示,最近一次GC是由于显式的System.gc()调用所引起的,当前时刻未进行GC。
-gcnew参数可以用于查看新生代的一些详细信息:
在这里插入图片描述
· TT:新生代对象晋升到老年代对象的年龄。
· MTT:新生代对象晋升到老年代对象的年龄最大值。
· DSS:所需的survivor区大小。
-gcnewcapacity参数可以详细输出新生代各个区的大小信息:
在这里插入图片描述
· S0CMX:s0区的最大值(KB)。
· S1CMX:s1区的最大值(KB)。
· ECMX:eden区的最大值(KB)。
-gcold用于展现老年代GC的概况:
在这里插入图片描述
-gcoldcapacity用于展现老年代的容量信息:
在这里插入图片描述
-gcpermcapacity用于展示永久区的使用情况:
在这里插入图片描述
-gcutil用于展示GC回收相关信息:
在这里插入图片描述
· S0:s0区使用的百分比。
· S1:s1区使用的百分比。
· E:eden区使用的百分比。
· O:老年代使用的百分比。
· P:永久区使用的百分比。

注意: jstat命令可以非常详细地查看Java应用程序的堆使用情况及GC情况。

jinfo命令----查看虚拟机参数

jinfo命令可以用来查看正在运行的Java应用程序的扩展参数,甚至支持在运行时修改部分参数。它的基本语法为:
在这里插入图片描述
其中option可以为以下信息。
·-flag:打印指定Java虚拟机的参数值。
·-flag [+|-]:设置指定Java虚拟机参数的布尔值。
·-flag=:设置指定Java虚拟机参数的值。
在很多情况下,Java应用程序不会指定所有的Java虚拟机参数。而此时,开发人员可能不知道某一个具体的Java虚拟机参数的默认值。在这种情况下,可能需要通过查找文档获取某个参数的默认值。这个查找过程可能是非常艰难的。但有了jinfo命令,开发人员可以很方便地找到Java虚拟机参数的当前值。下例显示了新生代对象晋升到老年代对象的最大年龄。在应用程序启动时,并没有指定这个参数,但通过jinfo命令可以查看这个参数的当前数值。
在这里插入图片描述
显示是否打印GC详细信息:
在这里插入图片描述
除了查找参数的值,jinfo命令也支持修改部分参数的数值,当然,这个修改能力是极其有限的。下例显示了通过jinfo命令对PrintGCDetails参数的修改,它可以在Java程序运行时,动态关闭或者打开这个开关。
在这里插入图片描述
注意:
使用jinfo命令不仅可以查看运行时某一个Java虚拟机参数的实际取值,甚至可以在运行时修改部分参数,并使之立即生效(并非所有参数都支持动态修改)。

jmap命令----导出堆到文件

jmap命令是一个多功能的命令。它可以生成Java程序的堆Dump文件,也可以查看堆内对象实例的统计信息、查看ClassLoader的信息及finalizer队列。下例使用jmap命令生成PID为2972的Java程序的对象统计信息,并输出到s.txt文件中。
在这里插入图片描述
输出文件结构如下:
在这里插入图片描述

可以看到,这个输出显示了内存中的实例数量和合计。jmap命令另一个更为重要的功能是得到Java程序的当前堆快照:

jmap -dump:format=b,file=./dumplog/heap.hprof 3339

在这里插入图片描述
本例中,将应用程序的堆快照输出到C盘heap.bin文件中。之后,可以通过多种工具分析该堆文件。比如,下文中提到的jhat工具或者Visual VM、MAT等工具。

注意: jmap可用于导出Java应用程序的堆快照。
此外,jmap还可以查看系统的ClassLoader的信息,如下所示:
在这里插入图片描述
可以看到,系统中有3个ClassCloader,并显示了它们的父子关系。同时,也显示了每个ClassLoader内部加载的类的数量和总大小。

通过jmap命令,还可以观察系统finalizer队列中的对象,一个不恰当的finalize()函数可能导致对象堆积在finalizer队列中。使用以下命令可以查看堆积在finalizer队列中的对象:
在这里插入图片描述
在这里插入图片描述
可以看到,在finalizer队列中,堆积了大量的geym.zbase.ch5.LongFinalize$LF对象实例和3个java.io.FileInputStream实例。

jhat命令----JDK自带的堆分析工具

使用jhat命令可以分析Java应用程序的堆快照内容。

说明:
jhat命令在JDK9、JDK10中已经被删除,官方建议用VisualVm代替,参考6.5.5节。

【示例6-9】以前文中jmap命令的输出堆文件heap.hprof为例。
在这里插入图片描述
在分析完成后,使用HTTP服务器展示其分析结果。在浏览器中访问http://127.0.0.1:7000,输出结果如图6.18所示。在默认页中,jhat服务器显示了所有的非平台类信息。单击链接,可以查看选中类的超类、ClassLoader及该类的实例等信息。此外,在页面底部,还为开发人员提供了其他查询方式,如图6.19所示。
在这里插入图片描述

jstack命令----查看线程堆栈

jstack命令用于导出Java应用程序的线程堆栈,语法为:
在这里插入图片描述
-l选项用于打印锁的附加信息。jstack命令会在控制台输出程序中所有的锁信息,可以使用重定向将输出保存到文件中,如:

jstack -l 3339 >./dumplog/jstack.txt

在这里插入图片描述
示例6-10】下例演示了一个简单的死锁,两个线程分别占用south锁和north锁,并同时请求对方占用的锁,导致死锁发生。
在这里插入图片描述
在这里插入图片描述
使用jstack命令打印上例的输出,部分输出结果如下:
在这里插入图片描述
从输出中,可以很容易地找到死锁,并同时显示了发生死锁的两个线程,以及死锁线程的持有对象和等待对象,帮助开发人员解决死锁问题。

注意: 通过jstack命令不仅可以得到线程堆栈,还能自动进行死锁检查,输出找到的死锁信息。

jstatd命令----远程主机信息收集

在本节之前所述的工具中,只涉及监控本机的Java应用程序,而在这些工具中,一些监控工具也支持对远程计算机的监控(如jps、jstat)。为了启用远程监控,需要配合使用jstatd命令。

jstatd命令是一个RMI服务端程序,它的作用相当于代理服务器,建立本地计算机与远程监控工具的通信。jstatd服务器将本机的Java应用程序信息传递到远程计算机,如图6.23所示。

在这里插入图片描述

jcmd命令----多功能命令行

在JDK 1.7以后,新增了一个命令行工具jcmd。它是一个多功能的工具,可以用来导出堆、查看Java进程、导出线程信息、执行GC等。

jcmd命令可以针对给定的Java虚拟机执行一条命令。首先来看一下如何使用jcmd命令列出当前系统中的所有Java虚拟机
在这里插入图片描述
参数-l表示列出所有的Java虚拟机,针对每一个虚拟机,jcmd命令可以使用help命令列出它们所支持的命令:
在这里插入图片描述
这里罗列的就是进程号2828虚拟机所支持的jcmd命令操作,下面介绍几个常用的命令。

(1)查看虚拟机启动时间VM.uptime:

在这里插入图片描述
jcmd命令也支持直接使用MainClass的名字来代替进程号,这样在编写脚本的时候也更为容易,如下所示:
在这里插入图片描述

(2)打印线程栈信息:

在这里插入图片描述

(3)查看系统中类的统计信息:

在这里插入图片描述

(4)导出堆信息:

在这里插入图片描述
GC.heap_dump接收一个参数作为堆Dump文件的输出路径,得
到堆文件后,可以使用MAT或者Visual VM等工具进行分析。

(5)获得系统的Properties内容:

在这里插入图片描述

(6)获得启动参数:

在这里插入图片描述

(7)获得所有性能统计相关数据。

通过jcmd命令,还可以获得所有的PerfData数据,如下所示:
在这里插入图片描述
在这个输出中,可以找到所有的性能统计相关的数据,作为示例,这里给出了活动线程数量、活动线程峰值等信息。从以上示例中可以看到,jcmd拥有jmap的大部分功能,并且在Oracle的官方网站上也推荐使用jcmd命令代替jmap命令。

hprof----性能统计工具

与前文中介绍的监控工具不同,hprof不是独立的监控工具,它只是一个Java agent工具。它可以用于监控Java应用程序在运行时的CPU信息和堆信息。使用java-agentlib:hprof=help命令可以查看

说明: hprof在JDK9、JDK10中已经被删除,官方建议用 VisualVM代替,参考6.5.5节和6.5.6节。

下面是hropf工具帮助信息的输出,加粗部分是常用的参数。

图形化虚拟机监控工具

JConsole

Console是JDK自带的图形化性能监控工具。通过JConsole工具,可以查看Java应用程序的运行概况,可以监控堆信息、永久区使用情况、类加载情况等。本节主要介绍JConsole工具的基本使用方法。

Visual VM

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值