JVM 性能监控与调优篇-2-命令行监控诊断工具
查看正在运行的Java进程
显示指定系统内所有的HotSpot虚拟机进程(查看虚拟机进程信息),可用于查询正在运行的虚拟机进程。
对于本地虚拟机进程来说,进程的本地虚拟机ID与操作系统的进程ID是一致的,它是唯一的。
命令
1 | # 查看正在运行的Java进程 |
option
option参数 | 说明 |
---|---|
-q |
仅仅显示LVMID(local virtual machine id),即本地虚拟机唯一id。不显示主类的名称等 |
-l |
输出应用程序主类的全类名或如果进程执行的是jar包,则输出jar完整路径 |
-m |
输出虚拟机进程启动时传递给主类main()的参数 |
-v |
列出虚拟机进程启动时的JVM参数 |
如果某Java进程关闭默认开启的UsePerfData
参数(即使用参数-XX :-UsePerfData
),那么jps命令(以及jstat)将无法探知该Java进程。
hostid
- RMI注册表中注册的主机名
- 如果想要远程监控主机上的java程序,需要安装
jstatd
- 对于具有更严格的安全实践的网络场所而言,可能使用一个自定义的策略文件来显示对特定的可信主机或网络的访问,尽管这种技术容易受到IP地址欺诈攻击
- 如果安全问题无法使用一个定制的策略文件来处理,那么最安全的操作是不运行jstatd服务器,而是在本地使用jstat和jps工具
查看JVM统计信息
jstat用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
在没有GUI图形界面,只提供纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。常用于检测垃圾回收问题以及内存泄漏问题。
命令
1 | # 查看JVM统计信息 |
option
类装载相关:
option参数 | 说明 |
---|---|
-class |
显示ClassLoader的相关信息:类的装载、卸载数量、总空间、类装载所消耗的时间等 |
垃圾回收相关:
option参数 | 说明 |
---|---|
-gc |
显示与GC相关的堆信息,包括Eden区、两个Survivor区、老年代、永久代等的容量、已用空间、GC时间合计等信息 |
-gccapacity |
显示内容与-gc 基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间 |
-gcutil |
显示内容与-gc 基本相同,但输出主要关注已使用空间占总空间的百分比 |
-gccause |
与-gcutil 功能一样,但是会额外输出导致最后一次或当前正在发生的GC的产生原因 |
-gcnew |
显示新生代GC状况 |
-gcnewcapacity |
显示内容与-gcnew 基本相同,输出主要关注使用到的最大、最小空间 |
-gcold |
显示老年代GC状况 |
-gcoldcapacity |
显示内容与-gcold 基本相同,输出主要关注使用到的最大、最小空间 |
-gcpermcapacity |
显示永久代使用到的最大、最小空间 |
JIT相关:
option参数 | 说明 |
---|---|
-compiler |
显示JIT编译器编译过的方法、耗时等信息 |
-printcompilation |
输出已经被JIT编译的方法 |
interval
用于指定输出统计数据的周期,单位为毫秒。即:查询间隔
count
用于指定查询的总次数
-t
在输出信息前加上一个Timestamp列,显示程序的运行时间。
-h
在周期性数据输出时,输出多少行数据后输出一个表头信息
说明
新生代相关:
- S0C是第一个幸存者区的大小(字节)
- S1C是第二个幸存者区的大小(字节)
- S0U是第一个幸存者区已使用的大小(字节)
- S1U是第二个幸存者区已使用的大小(字节)
- EC是Eden空间的大小(字节)
- EU是Eden空间已使用大小(字节)
老年代相关:
- OC是老年代的大小(字节)
- OU是老年代已使用的大小(字节)
方法区(元空间)相关:
- MC是方法区的大小
- MU是方法区已使用的大小
- CCSC是压缩类空间的大小
- CCSU是压缩类空间已使用的大小
其他:
- YGC是指从应用程序启动到采样时young gc次数
- YGCT是指从应用程序启动到采样时young gc消耗的时间(秒)
- FGC是指从应用程序启动到采样时full gc次数
- FGCT是指从应腻呈序启动到采样时full gc消耗的时间(秒)
- GCT是指从应用程序启动到采样时gc的总时间
jstat还可以用来判断是否出现内存泄漏。
第1步:在长时间运行的Java程序中,可以运行jstat命令连续获取多行性能数据,并取这几行数据中OU列(即已占用的老年代内存)的最小值。
第2步:然后每隔一段较长的时间重复一次上述操作,来获得多组OU最小值。如果这些值呈上涨趋势,则说明该Java程序的老年代内存已使用量在不断上涨,这意味着无法回收的对象在不断增加,因此很有可能存在内存泄漏。
实时查看和修改JVM配置参数
查看虚拟机配置参数信息,也可用于调整虚拟机的配置参数。
命令
1 | # 实时查看和修改JVM配置参数 |
option
拓展
VM参数 | 说明 |
---|---|
java -XX:+PrintFlagsInitial |
查看所有JVM参数启动的初始值 |
java -XX:+PrintFlagsFinal |
查看所有JVM参数的最终值 |
java -XX:+PrintCommandLineFlags |
查看已被用户或JVM设置过的详细的XX参数的名称和值 |
导出内存映像文件&内存使用情况
jmap可以获取dump文件(堆转储快照文件,二进制文件),还可以获取目标Java进程的内存相关信息,包括Java堆各区域的使用情况、堆中对象的统计信息、类加载信息等。
选项 | 说明 | |
---|---|---|
-dump |
生成Java堆转储快照(dump文件)。-dump:live 只保存堆中的存活对象 |
|
-heap |
输出整个堆空间的详细信息,包括GC使用、堆配置信息、内存使用信息 | |
-histo |
输出堆中对象的统计信息,包括类、实例数量和和合计容量。-histo:live 只统计堆中的存活对象 |
|
-permstat |
以ClassLoader为统计口径输出永久代的内存状态信息(仅Linux/Solaris平台有效) | |
-finalizerinfo |
显示在F-Queue中等待Finalizer线程执行finalize方法的对象(仅Linux/Solaris平台有效) | |
`-h | -help` | jmap 工具使用的帮助命令 |
-J <flag> |
传递参数给jmap启动的jvm |
导出内存映像文件
手动方式
1 | jmap -dump:format=b,file= <filename.hprof> <pid> |
自动方式
1 | # 程序发生OOM时,导出应用程序当前堆快照 |
显示堆内存相关信息
1 | jmap -heap pid |
其他用法
1 | # 查看系统的ClassLoader信息(Linux下使用) |
小结
由于jmap将访问堆中的所有对象,为了保证在此过程中不被应用线程干扰,jmap需要借助安全点机制,让所有线程停留在不改变堆中数据的状态。由jmap导出的堆快照必定是安全点位置的,这可能导致基于该堆快照的分析结果存在偏差。
另外,如果某个线程长时间无法跑到安全点,jmap将一直等下去。与前面讲的jstat则不同,垃圾回收器会主动将jstat所需要的摘要数据保存至固定位置之中,而jstat只需直接读取即可。
JDK自带堆分析工具
Sun JDK提供的jhat命令与jmap命令搭配使用,用于分析jmap生成的heap dump文件(堆转储快照)。
jhat内置一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,用户可以在浏览器中查看分析结果
使用jhat命令,就启动http服务,端口是7000,可以在浏览器里分析。
选项 | 说明 | ||
---|---|---|---|
`-stack false | true` | 关闭\ | 打开对象分配调用栈跟踪 |
`-refs false | true` | 关闭\ | 打开对象引用跟踪 |
-port port-number |
设置jhat HTTP Server的默认端口号,默认7000 | ||
-exclude exclude-file |
执行对象查询时需排除的数据成员 | ||
-baseline exclude-file |
指定一个基准堆转储 | ||
-debug int |
设置dug级别 | ||
-version |
启动后显示版本信息就退出 | ||
-J <flag> |
传入启动参数,如-J -Xmx512m |
打印JVM中线程快照
jstack用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。线程快照就是当前虚拟机内指定进程的每一条线程正在执行的方法堆栈的集合。
生成线程快照用于定位线程出现长时间停顿原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用jstack显示各个线程调用的堆栈情况。
Thread dump中几种状态:
状态 | 说明 |
---|---|
Deadlock | 死锁 |
Waiting on condition | 等待资源 |
Waiting on monitor entry | 等待获取监视器 |
Blocked | 阻塞 |
Runnable | 执行中 |
Suspended | 暂停 |
Object.wait()或TIMED_WAITING | 对象等待中 |
Parked | 停止 |
option
选项 | 说明 |
---|---|
-F |
当正常输出的请求不被响应时,强制输出线程堆栈 |
-l |
除堆栈外,显示关于锁的附加信息 |
-m |
如果调用到本地方法栈,可以显式C/C++的堆栈 |
-h |
帮助操作 |
多功能命令行
JDK 1.7后新增一个命令行工具jcmd,它是一个多功能的工具,可以用来实现前面除了jstat
外所有命令的功能。比如用它来导出堆、内存使用、查看Java进程、导出线程信息、执行GC、JVM运行时间等
1 | # 列出所有JVM进程 |
远程主机信息收集
些监控工具也支持对远程计算机的监控(如jps、jstat)。为启用远程监控,则需要配合使用jstatd 工具。
命令jstatd是一个RMI服务端程序,它的作用相当于代理服务器,建立本地计算机与远程监控工具的通信。jstatd服务器将本机的Java应用程序信息传递到远程计算机。