JVM性能监控与故障处理工具

栏目: Java · 发布时间: 5年前

内容简介:Java与C++之间有一堵由内存分配和垃圾收集技术所围成的“高墙”,墙里面的人想出去,墙外面的人想进来。在给一个系统定位问题的时候,知识、经验是关键基础,而工具是运用知识去处理数据的手段,这里的数据在JVM中包括:运行日志、异常堆栈、GC日志、线程快照(threaddump/javacore文件)、堆转储快照(headdump/hprof文件)等。经常使用适当的虚拟机监控和分析的工具可以加快我们分析数据、定位解决问题的速度。但是下面介绍的所有工具,都只是对知识技能的一层“封装”,吃透底层原理才是最重要的,工

Java与C++之间有一堵由内存分配和垃圾收集技术所围成的“高墙”,墙里面的人想出去,墙外面的人想进来。

概述

在给一个系统定位问题的时候,知识、经验是关键基础,而 工具 是运用知识去处理数据的手段,这里的数据在JVM中包括:运行日志、异常堆栈、GC日志、线程快照(threaddump/javacore文件)、堆转储快照(headdump/hprof文件)等。经常使用适当的虚拟机监控和分析的工具可以加快我们分析数据、定位解决问题的速度。但是下面介绍的所有工具,都只是对知识技能的一层“封装”,吃透底层原理才是最重要的,工具的使用是次要的。

JDK命令行工具

一般来说,Java开发人员在初学 Java 的时候就知道有 java.exejavac.exe 两个命令行工具,这是最开始我们写 Hello World 的时候用到的,但是却并不是所有Java程序员都知道除了这两个命令行工具外,JDK自带的 bin 目录下的其它很多 exe 工具的数量和功能是在不断的增加和提升的。

由于我个人使用的是 JDK1.8 版本,所以我们以windows下 JDK1.8 版本下 bin 目录工具为例,如果是 linux 或者macOS可能看到的不太一样。

JVM性能监控与故障处理工具

其中细心的人可以发现好像大多数工具都是17KB,嘿,难道是JDK开发团队在刻意跟我们炫耀高超编程技巧?其实当然不是,这只是因为上面的exe命令行工具大多数都是 jdk/lib/tools.jar 工具的一层很薄的封装而已,其中主要的功能实现都是在 tools 类库中实现的。

那么为啥要采用java代码来实现这些监控工具呢?

其实啊,主要是因为实际应用程序部署到生产环境后,无论是直接接触物理服务器还是远程Telnet到服务器上都可能受到限制,而借助 tools.jar 类库里面的工具,我们就可以直接在应用程序中实现强大的监控分析工具。

如果使用的是JDK1.5及之前版本的JDK的话,在程序启动的时候需要添加参数”-Dcom.sun.management.jmxremote”来开启JMX管理功能,因为其中监控工具大多数都是基于JMX的,而如果是JDK1.6之后的版本,那么JMX管理是默认开启的,即不需要手动添加参数。

常用的JDK监控和故障处理工具

名称 主要作用
jps(JVM Process Status Tool) 显示指定系统内所有的HotSpot虚拟机进程
jstat(JVM Statistics Monitoring Tool) 用于收集HotSpot虚拟机各方面的运行数据
jinfo(Configuration Info for Java) 显示虚拟机配置信息
jmap(Memory Map for Java) 生成虚拟机的内存转储快照(heapdump文件)
jhat(JVM Heap Dump Browser) 用于分析heapdump文件,会建立一个HTTP/HTML服务器,让用户可以在浏览器上查看分析结果
jstack(Stack Trace for Java) 显示虚拟机的线程快照

jps:虚拟机进程状况工具

ps取名其实和Unix的ps命令一样,也就是用来列出正在运行的虚拟机进程,并显示虚拟机执行主类,其实在windows下或者linux下ps命令也可以查询到虚拟机进程的id,但是如果同时启动了多个虚拟机进程,且无法通过进程名称定位时,那就只能依赖jps命令显示主类来查询虚拟机进程了。

jps命令格式:

jps [options] [hostid]

用法比较简单,比如我在本地启动了两个虚拟机进程,主类名称分别是 cn.bestzuo.MultiThreadcn.bestzuo.SynAddRunnable ,在使用 jps -l 命令查看进程:

C:\Program Files\Java\jdk1.8.0_191\bin> jps -l
+12256 cn.bestzuo.SynAddRunnable
11012 org.jetbrains.jps.cmdline.Launcher
+4696 cn.bestzuo.MultiThread
5480 sun.tools.jps.Jps
8408

上面绿色的两个进程就是虚拟机启动的进程,前面的数字表示进程id。

那么后面的 -l 是选择使用的参数,jps命令可以使用的参数如下:

选项 作用
-q 只输出LVMID,省略主类的名称
-m 输出虚拟机进程启动时传递给主类main()函数的参数
-l 输出主类的全名,如果进程执行的是jar包,输出Jar路径
-v 输出虚拟机进程启动时JVM参数

jstat:虚拟机统计信息监视工具

jstat用于监视虚拟机各种运行状态信息的命令行工具,它可以显示本地或者远程虚拟机中的类装载、内存、垃圾收集、JIT编译等运行数据,在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。

jstat命令格式为:

jstat [option vmid [interval[s|ms] [count]] ]

对于命令格式中的VMID和LVMID需要特别说明一下,如果是本地虚拟机进程,那么VMID和LVMID是一致的,如果是远程虚拟机进程,那么VMID的格式应该是:

[protocol:][//]lvmid[@hostname[:port]/servername]

其中参数interval和count代表查询间隔和次数,如果省略这两个参数,说明只查询一次。

假设需要每250毫秒查询一次进程id为2764垃圾收集情况,一共查询20次,那么命令应该是:

jstat -gc 2764 250 20

选项option代表用户想要查询的虚拟机信息,主要分三类:类装载、垃圾收集和运行期编译情况。

选项 作用
-class 监视类装载、卸载数量、总空间以及类装载所耗费的时间
-gc 监视java堆状况,包括Eden区、两个Survivor区、老年代、永久代容量、已用空间、GC时间合计等信息
-gccapacity 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-gcutil 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause 与-gcutil工具一样,但是会额外输出导致上一次GC产生的原因
-gcnew 监视新生代GC状况
-gcnewcapacity 监视内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
-gcold 监视老年代GC状况
-gcoldcapacity 监视内容与-gcold基本相同,输出主要关注使用到的最大、最小空间
-gcpermcapacity 输出永久代使用到的最大、最小空间
-compiler 输出JIT编译器编译过的方法、耗时等信息
-printcompilation 输出已经被JIT编译过的方法

由于jstat监视选项太多,因此只测试一下其中一项观察结果,依然测试主类 cn.bestzuo.SyncAddRunnable 主类,我们可以看到如下结果:

C:\Program Files\Java\jdk1.8.0_191\bin> jstat -gcutil 12256
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00  15.47  58.71   0.01  66.07  68.03      1    0.001     0    0.000    0.001

其中:

  • S0、S1表示两个Survivor区,其中S1区使用了15.47%的空间
  • E代表Eden区,即新生代使用了58.71%的空间
  • O代表老年代,老年代中使用了0.01%的空间
  • M表示元数据区,即metaspace,使用了66.07%的空间
  • CCS表示压缩使用比例
  • YGC即Minor GC,表示发生过一次
  • YGCT表示新生代GC耗时时间
  • FGC表示Full GC
  • FGCT表示Full GC耗时时间
  • GCT表示所有GC的总耗时

虽然jstat命令行工具不如后面提到的VisualVM直观,但是很多服务器管理员在没有GUI图形界面时,依然会使用该命令行工具来进行监视。

jinfo:Java配置信息工具

jinfo的作用是实时地查看和调整虚拟机各项参数。使用jps的-v参数可以查看虚拟机启动的时候显式指定的参数列表,但是如果想知道未被显示指定的参数的系统默认值,除了找资料外,就只能使用jinfo的-flag选项进行查询了。

jinfo的命令格式:

jinfo [option] pid

比如我们查询 CMSInitialingOccupancyFraction 参数值:

C:\Program Files\Java\jdk1.8.0_191\bin> jinfo -flag CMSInitiatingOccupancyFraction 12256
-XX:CMSInitiatingOccupancyFraction=-1

jmap:Java内存映像工具

jmap命令用于生成堆转储快照(一般称为headdump或dump文件)。如果不适用jmap命令,要想获取Java堆转储快照,也可以采取其它一些比较”暴力“的手段,比如使用 -XX:+HeapDumpOnOutOfMemoryError 参数,可以让虚拟机在OOM异常出现之后自动生成dump文件,通过 -XX:+HeapDumpOnCtrlBreak 参数则可以使用 [Ctrl]+[Break] 键让虚拟机生成dump文件,又或者在Linux系统下通过 Kill -3 命令发送进程退出信号”吓唬“一下虚拟机,也能拿到dump文件。

当然,jmap的作用并不仅仅是拿到dump文件,它还可以查询 finalize 执行队列、Java堆和永久代的详细信息,如空间使用率、当前用的哪种收集器等。

和jinfo一样,jmap不少功能在windows平台下都是受限的,除了生成dump文件的-dump选项和用于查看每个类的实例、空间占用统计的-histo选项在所有操作系统都提供之外,其余选项只能在Linux/Solaris下使用。

jmap命令格式:

jmap [option] vmid

其中option选项的合法值和具体含义如下:

选项 作用
-dump 生成Java堆转储快照
-finliazeinfo 显示在F-Queue中等待的Finalizer线程执行finalize方法的对象,只在Linux/Solaris平台下生效
-heap 显示Java堆详细信息,如使用哪种垃圾收集器、参数配置、分代状况等,只在Linux/Solaris下有效
-histo 显示堆中对象统计信息,包括类、实例数量、合计容量
-permstat 以ClassLoader为统计口径显示永久代内存状态,Linux/Solaris下有效
-F 当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照,Linux/Solris下有效

比如如下测试:

C:\Users\IcyFenix\jmap -dump:format=b,file=eclipse.bin 3500
Dumping heap to C:\Users\IcyFenix\eclipse.bin ...
Heap dump file created

jhat:虚拟机堆转储快照分析工具

jhat命令主要与jmap命令搭配使用,可以分析jmap生成的堆转储快照。jhat内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后可以在浏览器中查看。

不过实际使用中,除非真的没有其它工具可以使用,否则一般不会直接使用jhat命令来分析dump文件,原因一是一般不会在部署应用程序的服务器上直接分析dump文件,即使可以这样做,也会尽量将dump文件复制到其它机器上进行分析,因为分析工作本身就是一个耗时并且消耗硬件资源的过程,既然能到其它机器上分析,那就没必要受到命令行工具的限制了;另外一个原因是jhat的分析功能较为简陋,其它更多的工具能分析出来的东西更多。

jstack:Java堆栈跟踪工具

jstack命令用于生成虚拟机当前时刻的线程快照(一般称之为yhreaddump或者javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的常见原因。线程出现停顿后可以使用jstack来查看各个线程间的调用堆栈,就可以知道没有响应的线程到底在后台做些什么,或者在等待什么资源。

jstack的命令格式:

jstack [option] vmid

jstack工具主要选项:

选项 作用
-F 当正常输出的请求不被响应时,强制输出线程堆栈
-l 除堆栈外,显示关于锁的附加信息
-m 如果调用到本地方法的话,可以显示C/C++的堆栈

比如我们运行一段死锁的程序,然后查看其锁的信息:

PS C:\Program Files\Java\jdk1.8.0_191\bin> jstack -l 1328
2019-05-14 20:45:30
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.191-b12 mixed mode):

省略堆栈信息
...

"VM Thread" os_prio=2 tid=0x0000000017f68000 nid=0x18c0 runnable

"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00000000030e9000 nid=0x9e8 runnable

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00000000030ea800 nid=0x223c runnable

"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x00000000030ec000 nid=0x16f4 runnable

"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x00000000030ee800 nid=0x3af4 runnable

"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x00000000030f1000 nid=0x1f94 runnable

"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x00000000030f2000 nid=0x1440 runnable

"VM Periodic Task Thread" os_prio=2 tid=0x0000000019ade000 nid=0x392c waiting on condition

JNI global references: 12


Found one Java-level deadlock:
=============================
"Thread-199":
  waiting to lock monitor 0x0000000019b95918 (object 0x00000000d5b7d5f0, a java.lang.Integer),
  which is held by "Thread-47"
"Thread-47":
  waiting to lock monitor 0x00000000031cd708 (object 0x00000000d5b7d5e0, a java.lang.Integer),
  which is held by "Thread-58"
"Thread-58":
  waiting to lock monitor 0x0000000019b95918 (object 0x00000000d5b7d5f0, a java.lang.Integer),
  which is held by "Thread-47"

Java stack information for the threads listed above:
===================================================
"Thread-199":
        at cn.bestzuo.SynAddRunnable.run(SynAddRunnable.java:13)
        - waiting to lock <0x00000000d5b7d5f0> (a java.lang.Integer)
        at java.lang.Thread.run(Thread.java:748)
"Thread-47":
        at cn.bestzuo.SynAddRunnable.run(SynAddRunnable.java:14)
        - waiting to lock <0x00000000d5b7d5e0> (a java.lang.Integer)
        - locked <0x00000000d5b7d5f0> (a java.lang.Integer)
        at java.lang.Thread.run(Thread.java:748)
"Thread-58":
        at cn.bestzuo.SynAddRunnable.run(SynAddRunnable.java:14)
        - waiting to lock <0x00000000d5b7d5f0> (a java.lang.Integer)
        - locked <0x00000000d5b7d5e0> (a java.lang.Integer)
        at java.lang.Thread.run(Thread.java:748)

Found 1 deadlock.

注意:

在JDK1.5中, java.lang.Thread 类新增了一个 getAllStackTraces() 方法用于获取虚拟机中所有线程的 StackTraceElement 对象。使用这个方法可以通过简单的几行代码就完成 jstack 的大部分功能,在实际项目中不妨调用这个方法做一个管理员页面,可以随时使用浏览器来查看线程堆栈。

JDK可视化工具

JDK中除了提供大量的命令行工具外,还有两个功能非常强大的可视化工具: JConsoleVisualVM ,这两个是JDK的正式成员。

其中 JConsole 是jdk1.5时期就已经提供的虚拟机监控工具,而 VisualVM 在JDK1.6 Update7中才首次发布,现在已经成为Sun(Oracle)主力推动的多合一故障处理工具,并且已经从JDK中分离出来成为可以独立发展的开源项目。

上面两者由于是可视化工具,所以这里就不再赘述,内置功能相当于把前面提到的jdk命令行工具实现可视化。


以上所述就是小编给大家介绍的《JVM性能监控与故障处理工具》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

UNIX编程艺术

UNIX编程艺术

[美] Eric S. Raymond / 姜宏、何源、蔡晓骏 / 电子工业出版社 / 2012-8 / 99.00元

《UNIX编程艺术》主要介绍了Unix系统领域中的设计和开发哲学、思想文化体系、原则与经验,由公认的Unix编程大师、开源运动领袖人物之一Eric S.Raymond倾力多年写作而成。包括Unix设计者在内的多位领域专家也为《UNIX编程艺术》贡献了宝贵的内容。《UNIX编程艺术》内容涉及社群文化、软件开发设计与实现,覆盖面广、内容深邃,完全展现了作者极其深厚的经验积累和领域智慧。一起来看看 《UNIX编程艺术》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具