深入理解java虚拟机 摘要
二、虚拟机性能监控与故障处理工具
1. JDK的命令行工具
名称 | 主要作用 |
---|---|
jps | JVM Process Status Tool,显示制定系统内错有的Hotspot虚拟机进程 |
jstat | JVM Statictics Monitoring Tool,用于收集HotSpot虚拟机各方面的运行数据 |
jinfo | Configuration Info for Java ,显示虚拟机配置信息 |
jmap | Memory Map for Java , 生成虚拟机的内存转储快照( heapdump 文件) |
jhat | JVM Heap Dump Browser , 用于分析 heapdump 文件 , 它会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果 |
jstack | Stack Trance for Java , 显示虚拟机的线程快照 |
(一) jps:虚拟机进程状况工具
可以列出正在运行的虚拟机进程,并显示虚拟机执行主类(Main Class,main()函数所在的类)名称以及这些进程的本地虚拟机唯一ID(Local Virtual Machine Identifier,LVMID)。
jps可以通过RMI协议查询开启了RMI服务的远程虚拟机进程状态,hostid为RMI注册表中注册的主机名。
格式
jps[options][hostid]
示例:
C:\Program Files\Java\jdk1.8.0_144\bin>jps -l
4996 org.jetbrains.jps.cmdline.Launcher
884 org.jetbrains.jps.cmdline.Launcher
2888
6844 sun.tools.jps.Jps
8636 org.jetbrains.jps.cmdline.Launcher
主要选项:
选项 | 作用 |
---|---|
-q | 只输出 LVMID,省略主类的名称 |
-m | 输出虚拟机进程启动时传递给主类 main() 函数的参数 |
-l | 输出主类的全名,如果进程执行的是 jar 包,输出 jar 路径 |
-v | 输出虚拟机进程启动时JVM参数 |
(二)jstat:虚拟机统计信息监视工具
用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。
格式
jstat[option vmid[interval[s|ms][count]]]
参数interval和count代表查询间隔和次数,如果省略这两个参数,说明只查询一次。假设需要每250毫秒查询一次进程2764垃圾收集状况,一共查询20次,那命令应当是:
jstat-gc 2764 250 20
选项option代表着用户希望查询的虚拟机信息,主要分为3类:类装载、垃圾收集、运行期编译状况。
ps : 查询结果容量单位是KB 时间单位是 s , 很多博客写的是byte是错误的
选项:
选项 | 作用 |
---|---|
-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 编译器编译过的方法、耗时等信息 |
-printcompolation | 输出已经被 JIT 编译的方法 |
(三)jinfo:Java配置信息工具
jinfo(Configuration Info for Java)的作用是实时地查看和调整虚拟机各项参数。使用jps命令的-v参数可以查看虚拟机启动时显式指定的参数列表,但如果想知道未被显式指定的参数的系统默认值,除了去找资料外,就只能使用jinfo的-flag选项进行查询了
可以使用-flag[+|-]name或者-flag name=value修改一部分运行期可写的虚拟机参数值
格式:
jinfo[option]vmid
(四)jmap:Java内存映像工具
jmap(Memory Map for Java)命令用于生成堆转储快照(一般称为heapdump或dump文件)。jmap的作用并不仅仅是为了获取dump文件,它还可以查询finalize执行队列、Java堆和永久代的详细信息,如空间使用率、当前用的是哪种收集器等。
注意:这个jmap使用的时候jvm是处在假死状态的,只能在服务瘫痪的时候为了解决问题来使用,否则会造成服务中断。
格式
jmap[option]vmid
选项
选项 | 作用 |
---|---|
-dump | 生成java堆转存储快照。格式为: -dump:[live],format=b,file=,其中live自参数说明是否只dump出存活的对象 |
-finalizerinfo | 显示在F-Queue中等待Finalizer线程执行finalize方法的对象 |
-heap | 显示java堆详细信息,如使用哪种回收器、参数配置、分代状况等。 |
-histo | 显示堆中对象统计信息,包括类、实例数量、分代状况等。 |
-F | 当虚拟机进程对-dump选项没有响应时,可使用这个选项强制生成dump快照 |
(五) jhat:虚拟机堆转储快照分析工具
Sun JDK提供jhat(JVM Heap Analysis Tool)命令与jmap搭配使用,来分析jmap生成的堆转储快照。jhat内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,可以在浏览器中查看。不过实事求是地说,在实际工作中,除非笔者手上真的没有别的工具可用,否则一般都不会去直接使用jhat命令来分析dump文件,主要原因有二:一是一般不会在部署应用程序的服务器上直接分析dump文件,即使可以这样做,也会尽量将dump文件复制到其他机器上进行分析,因为分析工作是一个耗时而且消耗硬件资源的过程,既然都要在其他机器进行,就没有必要受到命令行工具的限制了
(六) jstack:Java堆栈跟踪工具
jstack(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照(一般称为threaddump或者javacore文件)。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的常见原因。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做些什么事情,或者等待着什么资源。
格式:
jstack[option]vmid
选项
选项 | 作用 |
---|---|
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-l | 除堆栈外,显示关于锁的附加信息 |
-m | 如果调用到本地方法的话,可以显示C\C++的堆栈 |
示例
E:\gitworkspace\agent-backend>jstack -l 5296
2018-02-26 11:01:36
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.144-b01 mixed mode):
"http-nio-8080-Acceptor-0" #31 daemon prio=5 os_prio=0 tid=0x000000001f048800 nid=0x17fc runnable [0x000000002799f000]
java.lang.Thread.State: RUNNABLE
at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)
at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)
- locked <0x0000000082b09878> (a java.lang.Object)
at org.apache.tomcat.util.net.NioEndpoint$Acceptor.run(NioEndpoint.java:692)
at java.lang.Thread.run(Thread.java:748)
Locked ownable synchronizers:
- None
PS: 在JDK 1.5中,java.lang.Thread类新增了一个getAllStackTraces()方法用于获取虚拟机中所有线程的StackTraceElement对象。使用这个方法可以通过简单的几行代码就完成jstack的大部分功能,在实际项目中不妨调用这个方法做个管理员页面,可以随时使用浏览器来查看线程堆栈