Java 故障处理工具

jps

JVM Process Status Tool,虚拟机进程状况工具。

除了名字像 UNIX 的 ps 命令之外,它的功能也和 ps 命令类似:可以列出正在运行的虚拟机进程,并显示虚拟机执行主类 (Main Class,main() 函数所在的类) 名称以及这些进程的本地虚拟机唯一 ID (LVMID,Local Virtual Machine Identifier)。其他的 JDK 工具大多需要输入它查询到的 LVMID 来确定要监控的是哪一个虚拟机进程。

对于本地虚拟机进程来说,LVMID 与操作系统的进程 ID(PID,Process Identifier)是一致的,使用 Windows 的任务管理器或者 UNIX的 ps 命令也可以查询到虚拟机进程的LVMID,但如果同时启动了多个虚拟机进程,无法根据进程名称定位时,那就必须依赖 jps 命令显示主类的功能才能区分了。

命令格式:

jps [options] [hostid]

常用选项:

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

执行样例:

jps -l
2388 D:\Develop\glassfish\bin\..\modules\admin-cli.jar
2764 com.sun.enterprise.glassfish.bootstrap.ASMain
3788 sun.tools.jps.Jps

jps 还可以通过 RMI (Remote Method Invocation, 远程方法调用) 协议查询开启了 RMI 服务的远程虚拟机进程状态,参数 hostid 为 RMI 注册表中注册的主机名。

jstat

JVM Statistics Monitoring Tool,虚拟机统计信息监视工具。

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

命令格式:

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

如果是本地虚拟机进程,VMID 与 LVMID 是一致的;

如果是远程虚拟机进程,那 VMID 的格式应当是:

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

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

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

jstat -gc 2764 250 20

选项 option 代表用户希望查询的虚拟机信息,主要分为三类:类加载、垃圾收集、运行期编译状
况。

在这里插入图片描述

执行样例:

jstat -gcutil 2764
S0   S1   E    O     P     YGC YGCT  FGC FGCT   GCT
0.00 0.00 6.20 41.42 47.20 16  0.105 3   0.472  0.577

查询结果表明:这台服务器的新生代 Eden 区(E,表示Eden)使用了 6.2% 的空间,2 个 Survivor 区(S0、S1,表示Survivor0、Survivor1)里面都是空的,老年代(O,表示Old)和永久代(P,表示 Permanent)则分别使用了 41.42% 和 47.20% 的空间。程序运行以来共发生 Minor GC(YGC,表示Young GC)16次,总耗时0.105秒;发生 Full GC(FGC,表示Full GC)3次,总耗时(FGCT,表示Full GC Time)为0.472秒;所有GC总耗时(GCT,表示GC Time)为 0.577 秒。

jinfo

Configuration Info for Java,Java 配置信息工具。

作用是实时查看和调整虚拟机各项参数。使用 jps 命令的 -v 参数可以查看虚拟机启动时显式指定的参数列表,但如果想知道未被显式指定的参数的系统默认值,除了去找资料外,就只能使用 jinfo 的 -flag 选项进行查询了(如果只限于 JDK 6 或以上版本的话,使用 java-XX:+PrintFlagsFinal查看参数默认值也是一个很好的选择)。

jinfo 还可以使用 -sysprops 选项把虚拟机进程的System.getProperties()的内容打印出来。这个命令在 JDK 5 时期已经随着 Linux 版的 JDK 发布,当时只提供了信息查询的功能,JDK 6 之后,jinfo 在 Windows 和 Linux 平台都有提供,并且加入了在运行期修改部分参数值的能力(可以使用-flag[+|-]name 或者 -flag name=value 在运行期修改一部分运行期可写的虚拟机参数值)。在 JDK 6 中,jinfo 对于Windows 平台功能仍然有较大限制,只提供了最基本的-flag选项。

命令格式:

jinfo [option] pid

执行样例:

查询 CMSInitiatingOccupancyFraction 参数值。

jinfo -flag CMSInitiatingOccupancyFraction 1444
-XX:CMSInitiatingOccupancyFraction=85

jmap

Memory Map for Java,Java 内存映像工具。用于生成堆转储快照(一般称为 heapdump 或 dump 文件)。

如果不使用 jmap 命令,要想获取 Java 堆转储快照也还有一些比较“暴力”的手段:

  • -XX:+HeapDumpOnOutOfMemoryError 参数,可以让虚拟机在内存溢出异常出现之后自动生成堆转储快照文件。
  • -XX:+HeapDumpOnCtrlBreak 参数则可以使用 [Ctrl]+[Break] 键让虚拟机生成堆转储快照文件。
  • 在Linux系统下通过 Kill -3 命令发送进程退出信号“恐吓”一下虚拟机,也能顺利拿到堆转储快照。

jmap 的作用并不仅仅是为了获取堆转储快照,它还可以查询 finalize 执行队列、Java 堆和方法区的详细信息,如空间使用率、当前用的是哪种收集器等。

和 jinfo 命令一样,jmap 有部分功能在 Windows 平台下是受限的,除了生成堆转储快照的 -dump 选项和用于查看每个类的实例、空间占用统计的 -histo 选项在所有操作系统中都可以使用之外,其余选项都只能在 Linux/Solaris 中使用。

命令格式:

jmap [option] vmid

option选项的合法值与具体含义如表所示:

在这里插入图片描述

执行样例:

使用 jmap 生成一个正在运行的 Eclipse 的堆转储快照文件,例子中的 3500 是通过 jps 命令查询到的 LVMID。

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

jhat

JVM Heap Analysis Tool,虚拟机堆转储快照分析工具。

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

实事求是地说,在实际工作中,除非手上真的没有别的工具可用,否则多数人是不会直接使用 jhat 命令来分析堆转储快照文件的,主要原因有两个方面。一是一般不会在部署应用程序的服务器上直接分析堆转储快照,即使可以这样做,也会尽量将堆转储快照文件复制到其他机器上进行分析,因为分析工作是一个耗时而且极为耗费硬件资源的过程,既然都要在其他机器上进行,就没有必要再受命令行工具的限制了。另外一个原因是 jhat 的分析功能相对来说比较简陋,VisualVM,以及专业用于分析堆转储快照文件的 Eclipse Memory Analyzer、IBM HeapAnalyzer 等工具,都能实现比 jhat 更强大专业的分析功能。

执行样例:使用 jhat 分析上一节采用 jmap 生成的 Eclipse IDE 的内存快照文件。

jhat eclipse.bin
Reading from eclipse.bin...
Dump file created Fri Nov 19 22:07:21 CST 2010
Snapshot read, resolving...
Resolving 1225951 objects...
Chasing references, expect 245 dots....
Eliminating duplicate references...
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

屏幕显示“Server is ready.”的提示后,用户在浏览器中输入http://localhost:7000/可以看到分析结果。

分析结果默认以包为单位进行分组显示,分析内存泄漏问题主要会使用到其中的 “HeapHistogram” (与jmap -histo功能一样) 与 OQL 页签的功能,前者可以找到内存中总容量最大的对象,后者是标准的对象查询语言,使用类似 SQL 的语法对内存中的对象进行查询统计。

jstack

Stack Trace for Java,Java堆栈跟踪工具。

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

命令格式:

jstack [option] vmid

option 选项的合法值与具体含义如下所示:

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

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

参考
《深入理解 Java 虚拟机》第三版

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章