【深入理解java虚拟机】JVM故障处理工具介绍

前言

大家都知道JDK的bin目录中有java.exe、 javac.exe这样的命令行工具,这些工具主要是用于监视虚拟机运行状态和进行故障处理的工具。这些故障处理工具并不单纯是被Oracle公司作为“礼物”附赠给JDK的使用者,根据软件可用性和授权的不同,可以把它们划分成三类:

  • 商业授权工具: 主要是JMC(Java Mission Control)及它要使用到的JFR(Java Flight Recorder),JMC这个原本来自于JRockit的运维监控套件从JDK 7 Update 40开始就被集成到OracleJDK中,
    JDK11之前都无须独立下载,但是在商业环境中使用它则是要付费的。

  • 正式支持工具:这一类工具属于被长期支持的工具,不同平台、不同版本的JDK之间,这类工具可能会略有差异,但是不会出现某一个工具突然消失的情况。

  • 实验性工具: 这一类工具在它们的使用说明中被声明为“没有技术支持,并且是实验性质的”(Unsupported and Experimental)产品,日后可能会转正,也可能会在某个JDK版本中无声无息地消失。但事实上它们通常都非常稳定而且功能强大,也能在处理应用程序性能问题、定位故障时发挥很大的作用。

一、jps:虚拟机进程状况工具

jps( JVM Process Status Tool)功能:可以列出正在运行的虚拟机进程,并显示虚拟机执行主类( Main Class,main()函数所在的类)名称以及这些进程的本地虚拟机唯一ID( LVMID, Local Virtual Machine Identifier)。

命令格式:

jps [ options ] [ hostid ]

示例:

jps
1764 RemoteMavenServer
18516 Launcher
17868 Jps

选项:

选项描述
-q只输出进程ID,忽略主类信息
-l输出主类全名,或者执行JAR包则输出路径
-m输出虚拟机进程启动时传递给主类main()函数的参数
-v输出虚拟机进程启动时的JVM参数

一、一 输出远程机器信息

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

jps 链接远程输出JVM信息,需要注册RMI,否则会报错:

jps -lv 127.0.0.1
RMI Registry not available at 127.0.0.1:1099
Connection refused to host: 127.0.0.1; nested exception is:
        java.net.ConnectException: Connection refused: connect

1、注册RMI开启 jstatd 在你的C:\Program Files\Java\jdk1.8.0_91\bin目录下添加名称为 jstatd.all.policy 的文件。

jstatd.all.policy 文件内容如下:

grant codebase "file:${java.home}/../lib/tools.jar" {
   permission java.security.AllPermission;
};

2、添加好配置文件后,在 bin 目录下注册添加的 jstatd.all.policy 文件:

C:\Program Files\Java\jdk1.8.0_91\bin>jstatd -J-Djava.security.policy=jstatd.all.policy

成功示例如下:

C:\Users\Administrator>jps -lv 127.0.0.1
12708 sun.tools.jps.Jps -Denv.class.path=.;G:\Java\jdk1.8.0_91\lib\dt.jar;G:\Java\jdk1.8.0_91\lib\tools.jar; -Dapplication.home=C:\Program Files\Java\jdk1.8.0_91 -Xms8m
16116  exit -Xms128m -Xmx3096m -XX:ReservedCodeCacheSize=512m -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=100 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -XX:+HeapDumpOnOutOfMemoryError
 -Didea.vendor.name=JetBrains -Didea.paths.selector=IntelliJIdea2021.1 -XX:ErrorFile=C:\Users\Administrator\java_error_in_idea64_%p.log -XX:HeapDumpPath=C:\Users\Administrator\java_error_in_idea64.hprof
1764 org.jetbrains.idea.maven.server.RemoteMavenServer -Djava.awt.headless=true -Dmaven.defaultProjectBuilder.disableGlobalModelCache=true -Didea.version=2021.1.2 -Didea.maven.embedder.version=3.1.1 -Xmx768m -Dfile.e
18516 org.jetbrains.jps.cmdline.Launcher -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Djdt.compiler.useSingleThread=true -Dpreload.project.path=G:/ideawork -Dpreload.config.path=G:/IntelliJ IDEA 2021.1.
net.preferIPv4Stack=true -Dio.netty.initialSeedUniquifier=1570513135976058670 -Dfile.encoding=GBK -Duser.language=zh -Duser.country=CN -Didea.paths.selector=IntelliJIdea2021.1 -Didea.home.path=G:\IntelliJ IDEA 2021.1
a2021.1/.IntelliJIdea/system/log/build-log -Djps.fallback.jdk.hom
2684 sun.tools.jstatd.Jstatd -Denv.class.path=.;G:\Java\jdk1.8.0_91\lib\dt.jar;G:\Java\jdk1.8.0_91\lib\tools.jar; -Dapplication.home=C:\Program Files\Java\jdk1.8.0_91 -Xms8m -Djava.security.policy=jstatd.all.policy

参数组合:

jps -lm 127.0.0.1

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

jstat(JVM Statistics Monitoring Tool),用于监视虚拟机各种运行状态信息。它可以查看本地或者远程虚拟机进程中,类加载、内存、垃圾收集、即时编译等运行时数据。

命令格式:

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

vmid:如果是查看远程机器,需要按照此格式:[protocol:][//]lvmid[@hostname[:port]/servername]

interval和count,表示查询间隔和次数,比如每隔1000毫秒查询一次进程ID的gc收集情况,每次查询5次。jstat -gc 111552 1000 3

选项主要分为三类:类加载、垃圾收集、运行期编译状况:

选项描述
-class监视类加载、卸载数量、总空间以及类装载所耗费时长
-gc监视 Java 堆情况,包括Eden区、2个 Survivor区、老年代、永久代或者jdk1.8元空间等,容量、已用空间、垃圾收集时间合计等信息
-gccapacity监视内容与-gc基本一致,但输出主要关注 Java 堆各个区域使用到的最大、最小空间
-gcutil监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause与 -gcutil 功能一样,但是会额外输出导致上一次垃圾收集产生的原因
-gcnew监视新生代垃圾收集情况
-gcnewcapacity监视内容与 -gcnew 基本相同,输出主要关注使用到的最大、最小空间
-gcold监视老年代垃圾收集情况
-gcoldcapacity监视内容与 -gcold 基本相同,输出主要关注使用到的最大、最小空间
-compiler输出即时编译器编译过的方法、耗时等信息
-printcompilation输出已经被即时编译的方法
-gcpermcapacityjdk1.7 及以下,永久代空间统计
-gcmetacapacityjdk1.8,元空间统计

示例:

C:\Users\Administrator>jstat -class 14944 1000 5
Loaded  Bytes  Unloaded  Bytes     Time
  6216 11190.6        1     0.9       4.70
  6216 11190.6        1     0.9       4.70
  6216 11190.6        1     0.9       4.70

C:\Users\Administrator>jstat -compiler 14944 1000 5
Compiled Failed Invalid   Time   FailedType FailedMethod
    3290      0       0     7.73          0
    3290      0       0     7.73          0
C:\Users\Administrator>jstat -gcutil 14944 1000 5
  S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
  0.00  34.71  89.33   6.49  94.64  91.92      5    0.080     1    0.048    0.128
  0.00  34.71  89.33   6.49  94.64  91.92      5    0.080     1    0.048    0.128


C:\Users\Administrator>jstat -gc 14944 1000 5
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC
6656.0 10752.0  0.0   3732.1 131072.0 117082.2  82944.0     5384.1   28416.0 26893.9 3840.0 3529.8      5    0.080   1

三、jinfo: Java配置信息工具

jinfo( Configuration Info for Java)的作用是实时查看和调整虚拟机各项参数。

命令格式:

jinfo [ option ] pid

示例:

C:\Users\Administrator>jinfo -flag MetaspaceSize 14944
-XX:MetaspaceSize=21807104

四、jmap: Java内存映像工具

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

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

命令格式:

jmap [ option ] pid

option:选项参数

pid:需要打印配置信息的进程ID

executable:产生核心dump的Java可执行文件

core:需要打印配置信息的核心文件

server-id:可选的唯一id,如果相同的远程主机上运行了多台调试服务器,用此选项参数标识服务器

remote server IP or hostname: 远程调试服务器的IP地址或主机名

选项:

选项描述
-dump生成 Java 堆转储快照。
-finalizerinfo显示在F-Queue中等待Finalizer线程执行finalize方法的对象。Linux平台
-heap显示 Java 堆详细信息,比如:用了哪种回收器、参数配置、分代情况。Linux平台
-histo显示堆中对象统计信息,包括类、实例数量、合计容量
-permstat显示永久代内存状态,jdk1.7,永久代
-F当虚拟机进程对 -dump 选项没有响应式,可以强制生成快照。Linux平台

堆转储文件示例:

jmap -dump:live,format=b,file=heap.bin 14944
C:\Users\Administrator>jmap -dump:format=b,file=idea.bin 14944
Dumping heap to C:\Users\Administrator\idea.bin ...
Heap dump file created

打印加载类示例:

C:\Users\Administrator>jmap -clstats 14944
Attaching to process ID 14944, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.91-b15
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness.......liveness analysis may be inaccurate ...
class_loader    classes bytes   parent_loader   alive?  type

<bootstrap>     1698    2983149   null          live    <internal>
0x00000007736a41e8      1       880     0x00000006c1c14038      dead    sun/reflect/DelegatingClassL

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

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

不过在实际工作中,除非手上真的没有别的工具可用,否则多数人是不会直接使用jhat命令来分析堆转储快照文件的,主要原因有两个方面:

  • 一是一般不会在部署应用程序的服务器上直接分析堆转储快照,即使可以这样做,也会尽量将堆转储快照文件复制到其他机器上进行分析,因为分析工作是一个耗时而且极为耗费硬件资源的过程,既然都要在其他机器上进行,就没有必要再受命令行工具的限制了。

  • 另外一个原因是jhat的分析功能相对来说比较简陋,后文将会介绍到的VisualVM,以及专业用于分析堆转储快照文件的Eclipse Memory Analyzer、 IBM HeapAnalyzer等工具,都能实现比jhat更强大专业的分析功能。下列代码清单演示了使用jhat分析上一节采用jmap生成的Eclipse IDE的内存快照文件。

示例:

C:\Users\Administrator>jhat idea.bin
Reading from idea.bin...
Dump file created Wed Oct 26 20:48:34 CST 2022
Snapshot read, resolving...
Resolving 1394404 objects...
Chasing references, expect 278 dots...................................................................................
Eliminating duplicate references......................................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

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

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

六、jstack: Java堆栈跟踪工具

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

命令格式:

jstack [ option ] vmid

选项:

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

示例:

jstack -l 14944

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

<%@ page import="java.util.Map"%>
<html>
<head>
<title>服务器线程信息</title>
</head>
<body>
<pre>
<%
	for (Map.Entry<Thread, StackTraceElement[]> stackTrace : Thread.getAllStack-Traces().entrySet()) {
		Thread thread = (Thread) stackTrace.getKey();
		StackTraceElement[] stack = (StackTraceElement[]) stackTrace.getValue();
		if (thread.equals(Thread.currentThread())) {
		continue;
		}
		out.print("\n线程: " + thread.getName() + "\n");
		for (StackTraceElement element : stack) {
		out.print("\t"+element+"\n");
		}
	}
%>
</pre>
</body>
</html>

七、基础工具总结

下面表罗列了JDK附带的全部(包括曾经存在但已经在最新版本中被移除的)工具及其简要用途,在高版本的JDK中,这些工具大多已有了功能更为强大的替代品,例如JCMD、 JHSDB的命令行模式,但使用方法也是相似的,无论JDK发展到了什么版本,学习这些基础的工具命令并不会过时和浪费。

  • 基础工具:用于支持基本的程序创建和运行。

    在这里插入图片描述

  • 安全:用于程序签名、设置安全测试等。
    在这里插入图片描述

  • 国际化:用于创建本地语言文件。

    在这里插入图片描述

  • 远程方法调用:用于跨Web或网络的服务交互。
    在这里插入图片描述

Java IDL与RMI-IIOP:在JDK 11中结束了十余年的CORBA支持,这些工具不再提供。
在这里插入图片描述

  • 部署工具:用于程序打包、发布和部署。
    在这里插入图片描述

  • Java Web Start。
    在这里插入图片描述

  • 性能监控和故障处理:用于监控分析Java虚拟机运行信息,排查问题。
    在这里插入图片描述

  • WebService工具:与CORBA一起在JDK 11中被移除。
    在这里插入图片描述

  • REPL和脚本工具。
    在这里插入图片描述

在这里插入图片描述
点赞 收藏 关注
外事以刚日,内事以柔日

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三省同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值