JDK 命令行工具
主要介绍 jps、jstat、jinfo、jmap、jhat、jstatc 等几个JDK命令行工具。这些命令在 JDK 安装目录下的 bin 目录下:(Mac 也可以在如下目录中找到这些命令)
bogon:bin maozhengwei$ pwd
/usr/bin
-
jps
(JVM Process Status): 类似 Linux 的ps
命令。用户查看所有 Java 进程的启动类、传入参数和 Java 虚拟机参数等信息; -
jstat
( JVM Statistics Monitoring Tool): 用于收集 HotSpot 虚拟机各方面的运行数据; -
jinfo
(Configuration Info for Java) : Configuration Info forJava,显示虚拟机配置信息; -
jmap
(Memory Map for Java) :生成堆转储快照; -
jhat
(JVM Heap Dump Browser ) : 用于分析 heapdump 文件,它会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果; -
jstack
(Stack Trace for Java):生成虚拟机当前时刻的线程快照,线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合。
jps
:查看所有 Java 进程
jps (JVM Process Status)
输入命令:jps
bogon:Users maozhengwei$ jps
23252 Jps
22985 Launcher
1034
22986 QuartzApplication
1054 RemoteMavenServer
jps
:显示虚拟机执行主类名称以及这些进程的本地虚拟机唯一 ID(Local Virtual Machine Identifier,LVMID)。jps -q
:只输出进程的本地虚拟机唯一 ID。
bogon:Users maozhengwei$ jps -q
23266
22985
1034
22986
1054
jps -l
:输出主类的全名,如果进程执行的是 Jar 包,输出 Jar 路径。
bogon:Users maozhengwei$ jps -l
23273 sun.tools.jps.Jps
22985 org.jetbrains.jps.cmdline.Launcher
1034
22986 com.maozw.quartz.QuartzApplication
1054 org.jetbrains.idea.maven.server.RemoteMavenServer
jps -v
:输出虚拟机进程启动时 JVM 参数。
bogon:Users maozhengwei$ jps -v
22986 QuartzApplication -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=59764:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8
23274 Jps -Dapplication.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home -Xms8m
1054 RemoteMavenServer -Djava.awt.headless=true -Didea.version==2018.3.2 -Xmx768m -Didea.maven.embedder.version=3.3.9 -Dfile.encoding=UTF-8
jps -m
:输出传递给 Java 进程 main() 函数的参数。
jstat
: 监视虚拟机各种运行状态信息
jstat(JVM Statistics Monitoring Tool) 使用于监视虚拟机各种运行状态信息的命令行工具。 它可以显示本地或者远程(需要远程主机提供 RMI 支持)虚拟机进程中的类信息、内存、垃圾收集、JIT 编译等运行数据,在没有 GUI,只提供了纯文本控制台环境的服务器上,它将是运行期间定位虚拟机性能问题的首选工具。
jstat
命令使用格式:
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
常见的 option 如下:
-
jstat -class vmid
:显示 ClassLoader 的相关信息; -
jstat -compiler vmid
:显示 JIT 编译的相关信息; -
jstat -gc vmid
:显示与 GC 相关的堆信息; -
jstat -gccapacity vmid
:显示各个代的容量及使用情况; -
jstat -gcnew vmid
:显示新生代信息; -
jstat -gcnewcapcacity vmid
:显示新生代大小与使用情况; -
jstat -gcold vmid
:显示老年代和永久代的信息; -
jstat -gcoldcapacity vmid
:显示老年代的大小; -
jstat -gcpermcapacity vmid
:显示永久代大小; -
jstat -gcutil vmid
:显示垃圾收集信息;
另外,加上 -t
参数可以在输出信息上加一个 Timestamp 列,显示程序的运行时间。
jstat -class vmid
:显示 ClassLoader 的相关信息;
bogon:Users maozhengwei$ jstat -class 22986
Loaded Bytes Unloaded Bytes Time
1040 2036.9 0 0.0 0.23
jstat -compiler vmid
:显示 JIT 编译的相关信息;
bogon:Users maozhengwei$ jstat -compiler 22986
Compiled Failed Invalid Time FailedType FailedMethod
358 0 0 0.19 0
jstat -gc vmid
:显示与 GC 相关的堆信息;
比如 jstat -gc -h3 31736 10000 10
表示分析进程 id 为 31736 的 gc 情况,每隔 10000ms 打印一次记录,打印 10 次停止,每 3 行后打印指标头部。
bogon:Users maozhengwei$ jstat -gc -h3 22986 10000 5
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
10752.0 10752.0 0.0 0.0 65536.0 32847.7 175104.0 0.0 4480.0 774.5 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 0.0 65536.0 32847.7 175104.0 0.0 4480.0 774.5 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 0.0 65536.0 32847.7 175104.0 0.0 4480.0 774.5 384.0 75.9 0 0.000 0 0.000 0.000
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
10752.0 10752.0 0.0 0.0 65536.0 32847.7 175104.0 0.0 4480.0 774.5 384.0 75.9 0 0.000 0 0.000 0.000
10752.0 10752.0 0.0 0.0 65536.0 32847.7 175104.0 0.0 4480.0 774.5 384.0 75.9 0 0.000 0 0.000 0.000
jstat -gccapacity vmid
:显示各个代的容量及使用情况
bogon:Users maozhengwei$ jstat -gccapacity 22986
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
87040.0 1397760.0 87040.0 10752.0 10752.0 65536.0 175104.0 2796544.0 175104.0 175104.0 0.0 1056768.0 4480.0 0.0 1048576.0 384.0 0 0
jstat -gcnew vmid
:显示新生代信息
bogon:Users maozhengwei$ jstat -gcnew 22986
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
10752.0 10752.0 0.0 0.0 15 15 0.0 65536.0 32847.7 0 0.000
jstat -gcold vmid
:显示老年代和永久代的信息
bogon:Users maozhengwei$ jstat -gcold 22986
MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
4480.0 774.5 384.0 75.9 175104.0 0.0 0 0 0.000 0.000
不在进行一一列举了
jinfo
: 实时地查看和调整虚拟机各项参数
jinfo vmid
:输出当前 jvm 进程的全部参数和系统属性
- 第一部分是系统的属性,第二部分是 JVM 的参数。
bogon:Users maozhengwei$ jinfo 22986
Attaching to process ID 22986, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11
Java System Properties:
java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.131-b11
sun.boot.library.path = /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib
gopherProxySet = false
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = :
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level = unknown
sun.java.launcher = SUN_STANDARD
user.country = CN
user.dir = /Users/maozhengwei/D-disk/gitee/maozw-resource
java.vm.specification.name = Java Virtual Machine Specification
java.runtime.version = 1.8.0_131-b11
java.awt.graphicsenv = sun.awt.CGraphicsEnvironment
os.arch = x86_64
java.endorsed.dirs = /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/endorsed
line.separator =
java.io.tmpdir = /var/folders/z9/bccj76r51zng2ty_9wk4s0280000gn/T/
java.vm.specification.vendor = Oracle Corporation
os.name = Mac OS X
sun.jnu.encoding = UTF-8
java.library.path = /Users/maozhengwei/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
java.specification.name = Java Platform API Specification
java.class.version = 52.0
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
os.version = 10.14.4
http.nonProxyHosts = local|*.local|169.254/16|*.169.254/16
user.home = /Users/maozhengwei
user.timezone = Asia/Shanghai
java.awt.printerjob = sun.lwawt.macosx.CPrinterJob
file.encoding = UTF-8
java.specification.version = 1.8
user.name = maozhengwei
java.class.path = /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/deploy.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/jfxrt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/javaws.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jfxswt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/plugin.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/ant-javafx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/javafx-mx.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/packager.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/lib/tools.jar:/Users/maozhengwei/D-disk/gitee/maozw-resource/target/classes:/Users/maozhengwei/.m2/repository/org/quartz-scheduler/quartz/2.3.0/quartz-2.3.0.jar:/Users/maozhengwei/.m2/repository/com/mchange/mchange-commons-java/0.2.11/mchange-commons-java-0.2.11.jar:/Users/maozhengwei/.m2/repository/com/zaxxer/HikariCP-java6/2.3.13/HikariCP-java6-2.3.13.jar:/Users/maozhengwei/.m2/repository/org/slf4j/slf4j-api/1.7.7/slf4j-api-1.7.7.jar:/Users/maozhengwei/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.1.3.RELEASE/spring-boot-starter-web-2.1.3.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/boot/spring-boot-starter/2.1.3.RELEASE/spring-boot-starter-2.1.3.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/boot/spring-boot/2.1.3.RELEASE/spring-boot-2.1.3.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.3.RELEASE/spring-boot-autoconfigure-2.1.3.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.1.3.RELEASE/spring-boot-starter-logging-2.1.3.RELEASE.jar:/Users/maozhengwei/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/Users/maozhengwei/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/Users/maozhengwei/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.11.2/log4j-to-slf4j-2.11.2.jar:/Users/maozhengwei/.m2/repository/org/apache/logging/log4j/log4j-api/2.11.2/log4j-api-2.11.2.jar:/Users/maozhengwei/.m2/repository/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:/Users/maozhengwei/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:/Users/maozhengwei/.m2/repository/org/springframework/spring-core/5.1.5.RELEASE/spring-core-5.1.5.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/spring-jcl/5.1.5.RELEASE/spring-jcl-5.1.5.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:/Users/maozhengwei/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.1.3.RELEASE/spring-boot-starter-json-2.1.3.RELEASE.jar:/Users/maozhengwei/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.9.8/jackson-databind-2.9.8.jar:/Users/maozhengwei/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar:/Users/maozhengwei/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.9.8/jackson-core-2.9.8.jar:/Users/maozhengwei/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.8/jackson-datatype-jdk8-2.9.8.jar:/Users/maozhengwei/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.8/jackson-datatype-jsr310-2.9.8.jar:/Users/maozhengwei/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.8/jackson-module-parameter-names-2.9.8.jar:/Users/maozhengwei/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.1.3.RELEASE/spring-boot-starter-tomcat-2.1.3.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.16/tomcat-embed-core-9.0.16.jar:/Users/maozhengwei/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/9.0.16/tomcat-embed-el-9.0.16.jar:/Users/maozhengwei/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.16/tomcat-embed-websocket-9.0.16.jar:/Users/maozhengwei/.m2/repository/org/hibernate/validator/hibernate-validator/6.0.14.Final/hibernate-validator-6.0.14.Final.jar:/Users/maozhengwei/.m2/repository/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar:/Users/maozhengwei/.m2/repository/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar:/Users/maozhengwei/.m2/repository/com/fasterxml/classmate/1.3.4/classmate-1.3.4.jar:/Users/maozhengwei/.m2/repository/org/springframework/spring-web/5.1.5.RELEASE/spring-web-5.1.5.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/spring-beans/5.1.5.RELEASE/spring-beans-5.1.5.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/spring-webmvc/5.1.5.RELEASE/spring-webmvc-5.1.5.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/spring-aop/5.1.5.RELEASE/spring-aop-5.1.5.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/spring-context/5.1.5.RELEASE/spring-context-5.1.5.RELEASE.jar:/Users/maozhengwei/.m2/repository/org/springframework/spring-expression/5.1.5.RELEASE/spring-expression-5.1.5.RELEASE.jar:/Users/maozhengwei/.m2/repository/com/google/guava/guava/18.0/guava-18.0.jar:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = com.maozw.quartz.QuartzApplication
java.home = /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.lwawt.macosx.LWCToolkit
java.vm.info = mixed mode
java.version = 1.8.0_131
java.ext.dirs = /Users/maozhengwei/Library/Java/Extensions:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/ext:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java
sun.boot.class.path = /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/sunrsasign.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/classes
java.vendor = Oracle Corporation
file.separator = /
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeBig
sun.cpu.endian = little
socksNonProxyHosts = local|*.local|169.254/16|*.169.254/16
ftp.nonProxyHosts = local|*.local|169.254/16|*.169.254/16
sun.cpu.isalist =
VM Flags:
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 -XX:MaxHeapSize=4294967296 -XX:MaxNewSize=1431306240 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC
Command line: -javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=59764:/Applications/IntelliJ IDEA.app/Contents/bin -Dfile.encoding=UTF-8
jinfo -flag <name> vmid
:输出对应名称的参数的具体值。
- 比如输出 MaxHeapSize、
- 查看当前 jvm 进程是否开启打印 GC 日志 (
-XX:PrintGCDetails
:详细 GC 日志模式,这两个都是默认关闭的)。 - MaxTenuringThreshold 对象晋升到老年代的年龄阈值
bogon:Users maozhengwei$ jinfo -flag MaxTenuringThreshold 22986
-XX:MaxTenuringThreshold=15
bogon:Users maozhengwei$ jinfo -flag MaxHeapSize 22986
-XX:MaxHeapSize=4294967296
bogon:Users maozhengwei$ jinfo -flag PrintGC 22986
动态修改 jvm 的参数
使用 jinfo 可以在不重启虚拟机的情况下,可以动态的修改 jvm 的参数。尤其在线上的环境特别有用,请看下面的例子:
jinfo -flag [+|-]name vmid
开启或者关闭对应名称的参数。
bogon:Users maozhengwei$ jinfo -flag PrintGC 22986
-XX:-PrintGC
bogon:Users maozhengwei$ jinfo -flag -PrintGC 22986
bogon:Users maozhengwei$ jinfo -flag PrintGC 22986
-XX:-PrintGC
bogon:Users maozhengwei$ jinfo -flag +PrintGC 22986
bogon:Users maozhengwei$ jinfo -flag PrintGC 22986
-XX:+PrintGC
jmap
:生成堆转储快照
jmap
(Memory Map for Java)命令用于生成堆转储快照。如果不使用
jmap
命令,要想获取 Java 堆转储,可以使用-XX:+HeapDumpOnOutOfMemoryError
参数,可以让虚拟机在 OOM 异常出现之后自动生成 dump 文件。Linux 命令下可以通过
kill -3
发送进程退出信号也能拿到 dump 文件。
jmap
的作用并不仅仅是为了获取 dump 文件,它还可以查询 finalizer 执行队列、Java 堆和永久代的详细信息,如空间使用率、当前使用的是哪种收集器等。和jinfo
一样,jmap
有不少功能在 Windows 平台下也是受限制的。
示例:将指定应用程序的堆快照输出到桌面。后面,可以通过 jhat、Visual VM 等工具分析该堆文件。
bogon:D-disk maozhengwei$ jmap -dump:format=b,file=/Users/maozhengwei/D-disk/heap.hprof 22986
Dumping heap to /Users/maozhengwei/D-disk/heap.hprof ...
Heap dump file created
jhat
: 分析 heapdump 文件
jhat
用于分析 heapdump 文件,它会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果。
bogon:D-disk maozhengwei$ jhat heap.hprof
Reading from heap.hprof...
Dump file created Wed Jun 12 11:13:15 CST 2019
Snapshot read, resolving...
Resolving 97551 objects...
Chasing references, expect 19 dots...................
Eliminating duplicate references...................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
jstack
:生成虚拟机当前时刻的线程快照
jstack
(Stack Trace for Java)命令用于生成虚拟机当前时刻的线程快照。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合.
生成线程快照的目的主要是定位线程长时间出现停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的原因。线程出现停顿的时候通过jstack
来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做些什么事情,或者在等待些什么资源。
下面是一个线程死锁的代码。我们下面会通过 jstack
命令进行死锁检查,输出死锁信息,找到发生死锁的线程。
public class DeadLockDemo {
private static Object resource1 = new Object();//资源 1
private static Object resource2 = new Object();//资源 2
public static void main(String[] args) {
new Thread(() -> {
synchronized (resource1) {
System.out.println(Thread.currentThread() + "get resource1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "waiting get resource2");
synchronized (resource2) {
System.out.println(Thread.currentThread() + "get resource2");
}
}
}, "线程 1").start();
new Thread(() -> {
synchronized (resource2) {
System.out.println(Thread.currentThread() + "get resource2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "waiting get resource1");
synchronized (resource1) {
System.out.println(Thread.currentThread() + "get resource1");
}
}
}, "线程 2").start();
}
}
输出结果:
Thread[线程 1,5,main]get resource1
Thread[线程 2,5,main]get resource2
Thread[线程 1,5,main]waiting get resource2
Thread[线程 2,5,main]waiting get resource1
- 线程 A 通过 synchronized (resource1) 获得 resource1 的监视器锁,然后通过
Thread.sleep(1000);
让线程 A 休眠 1s 为的是让线程 B 得到执行然后获取到 resource2 的监视器锁。线程 A 和线程 B 休眠结束了都开始企图请求获取对方的资源,然后这两个线程就会陷入互相等待的状态,这也就产生了死锁。
通过 jstack
命令分析:
bogon:D-disk maozhengwei$ jps
23783 Jps
1034
22986 QuartzApplication
23772 DeadLockDemo
23773 Launcher
1054 RemoteMavenServer
bogon:D-disk maozhengwei$ jstack 23772
2019-06-12 11:30:30
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.131-b11 mixed mode):
"Attach Listener" #14 daemon prio=9 os_prio=31 tid=0x00007fba41027800 nid=0xa403 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"DestroyJavaVM" #13 prio=5 os_prio=31 tid=0x00007fba41a9a000 nid=0x1903 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"线程 2" #12 prio=5 os_prio=31 tid=0x00007fba41a8a800 nid=0x5903 waiting for monitor entry [0x00007000117c1000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.maozw.quartz.thread.DeadLockDemo.lambda$main$1(DeadLockDemo.java:33)
- waiting to lock <0x000000076ad02748> (a java.lang.Object)
- locked <0x000000076ad02758> (a java.lang.Object)
at com.maozw.quartz.thread.DeadLockDemo$$Lambda$2/492228202.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"线��� 1" #11 prio=5 os_prio=31 tid=0x00007fba41a8a000 nid=0xa703 waiting for monitor entry [0x00007000116be000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.maozw.quartz.thread.DeadLockDemo.lambda$main$0(DeadLockDemo.java:18)
- waiting to lock <0x000000076ad02758> (a java.lang.Object)
- locked <0x000000076ad02748> (a java.lang.Object)
at com.maozw.quartz.thread.DeadLockDemo$$Lambda$1/548246552.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #10 daemon prio=9 os_prio=31 tid=0x00007fba3f849000 nid=0x5703 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #9 daemon prio=9 os_prio=31 tid=0x00007fba3e83b000 nid=0x5503 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #8 daemon prio=9 os_prio=31 tid=0x00007fba43000000 nid=0x3903 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #7 daemon prio=9 os_prio=31 tid=0x00007fba3e83a800 nid=0x3c03 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #6 daemon prio=9 os_prio=31 tid=0x00007fba3e839800 nid=0x3803 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Monitor Ctrl-Break" #5 daemon prio=5 os_prio=31 tid=0x00007fba41a8b800 nid=0x3f03 runnable [0x0000700010fa9000]
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
- locked <0x000000076adcc128> (a java.io.InputStreamReader)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
- locked <0x000000076adcc128> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:64)
"Signal Dispatcher" #4 daemon prio=9 os_prio=31 tid=0x00007fba3e82a000 nid=0x3703 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=31 tid=0x00007fba42019000 nid=0x4803 in Object.wait() [0x0000700010da3000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
- locked <0x000000076ab08ec8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
"Reference Handler" #2 daemon prio=10 os_prio=31 tid=0x00007fba41007800 nid=0x4a03 in Object.wait() [0x0000700010ca0000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076ab06b68> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x000000076ab06b68> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=31 tid=0x00007fba3e829800 nid=0x3303 runnable
"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007fba3f003000 nid=0x1d07 runnable
"GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007fba42002800 nid=0x2a03 runnable
"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007fba3f801800 nid=0x5403 runnable
"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007fba3f802000 nid=0x5303 runnable
"GC task thread#4 (ParallelGC)" os_prio=31 tid=0x00007fba41803000 nid=0x5203 runnable
"GC task thread#5 (ParallelGC)" os_prio=31 tid=0x00007fba3f003800 nid=0x5003 runnable
"GC task thread#6 (ParallelGC)" os_prio=31 tid=0x00007fba3f004800 nid=0x4f03 runnable
"GC task thread#7 (ParallelGC)" os_prio=31 tid=0x00007fba3f005000 nid=0x4e03 runnable
"GC task thread#8 (ParallelGC)" os_prio=31 tid=0x00007fba3f803000 nid=0x4c03 runnable
"GC task thread#9 (ParallelGC)" os_prio=31 tid=0x00007fba42012800 nid=0x3103 runnable
"VM Periodic Task Thread" os_prio=31 tid=0x00007fba43001000 nid=0xa803 waiting on condition
JNI global references: 325
Found one Java-level deadlock:
=============================
"线程 2":
waiting to lock monitor 0x00007fba42015ec8 (object 0x000000076ad02748, a java.lang.Object),
which is held by "线程 1"
"线程 1":
waiting to lock monitor 0x00007fba420186a8 (object 0x000000076ad02758, a java.lang.Object),
which is held by "线程 2"
Java stack information for the threads listed above:
===================================================
"线程 2":
at com.maozw.quartz.thread.DeadLockDemo.lambda$main$1(DeadLockDemo.java:33)
- waiting to lock <0x000000076ad02748> (a java.lang.Object)
- locked <0x000000076ad02758> (a java.lang.Object)
at com.maozw.quartz.thread.DeadLockDemo$$Lambda$2/492228202.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"线程 1":
at com.maozw.quartz.thread.DeadLockDemo.lambda$main$0(DeadLockDemo.java:18)
- waiting to lock <0x000000076ad02758> (a java.lang.Object)
- locked <0x000000076ad02748> (a java.lang.Object)
at com.maozw.quartz.thread.DeadLockDemo$$Lambda$1/548246552.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
bogon:D-disk maozhengwei$
可以看到 jstack
命令已经帮我们找到发生死锁的线程的具体信息。
JDK 可视化分析工具
JConsole:Java 监视与管理控制台
JConsole 是基于 JMX 的可视化监视、管理工具。可以很方便的监视本地及远程服务器的 java 进程的内存使用情况。
- 你可以在控制台输出
console
命令启动或者在 JDK 目录下的 bin 目录找到jconsole.exe
然后双击启动。 - mac也可以直接在控制台进入改命令路径,然后直接执行改命令,如下
连接 Jconsole
bogon:bin maozhengwei$ jconsole
- 如果需要使用 JConsole 连接远程进程,可以在远程 Java 程序启动时加上下面这些参数:
-Djava.rmi.server.hostname=外网访问 ip 地址
-Dcom.sun.management.jmxremote.port=60001 //监控的端口号
-Dcom.sun.management.jmxremote.authenticate=false //关闭认证
-Dcom.sun.management.jmxremote.ssl=false
- 在使用 JConsole 连接时,远程进程地址如下:
外网访问 ip 地址:60001
查看 Java 程序概况
内存监控
JConsole 可以显示当前内存的详细信息。不仅包括堆内存/非堆内存的整体信息,还可以细化到 eden 区、survivor 区等的使用情况,如下图所示。
点击右边的“执行 GC(G)”按钮可以强制应用程序执行一个 Full GC。
- 新生代 GC(Minor GC):指发生新生代的的垃圾收集动作,Minor GC 非常频繁,回收速度一般也比较快。
- 老年代 GC(Major GC/Full GC):指发生在老年代的 GC,出现了 Major GC 经常会伴随至少一次的 Minor GC(并非绝对),Major GC 的速度一般会比 Minor GC 的慢 10 倍以上。
线程监控
类似我们前面讲的 jstack
命令,不过这个是可视化的。
最下面有一个"检测死锁 (D)"按钮,点击这个按钮可以自动为你找到发生死锁的线程以及它们的详细信息 。我们查看之前死锁的那个进程(pid 23772):
VM概要
VM概要中会针对当前链接信息,运行时间以及虚拟机信息,线程计数,内存大小等进行概览统计,如下图:
Visual VM:多合一故障处理工具
VisualVM 提供在 Java 虚拟机 (Java Virutal Machine, JVM) 上运行的 Java 应用程序的详细信息。在 VisualVM 的图形用户界面中,您可以方便、快捷地查看多个 Java 应用程序的相关信息。Visual VM 官网:https://visualvm.github.io/ 。Visual VM 中文文档:https://visualvm.github.io/documentation.html。
下面这段话摘自《深入理解 Java 虚拟机》。
VisualVM(All-in-One Java Troubleshooting Tool)是到目前为止随 JDK 发布的功能最强大的运行监视和故障处理程序,官方在 VisualVM 的软件说明中写上了“All-in-One”的描述字样,预示着他除了运行监视、故障处理外,还提供了很多其他方面的功能,如性能分析(Profiling)。VisualVM 的性能分析功能甚至比起 JProfiler、YourKit 等专业且收费的 Profiling 工具都不会逊色多少,而且 VisualVM 还有一个很大的优点:不需要被监视的程序基于特殊 Agent 运行,因此他对应用程序的实际性能的影响很小,使得他可以直接应用在生产环境中。这个优点是 JProfiler、YourKit 等工具无法与之媲美的。
VisualVM 基于 NetBeans 平台开发,因此他一开始就具备了插件扩展功能的特性,通过插件扩展支持,VisualVM 可以做到:
- 显示虚拟机进程以及进程的配置、环境信息(jps、jinfo)。
- 监视应用程序的 CPU、GC、堆、方法区以及线程的信息(jstat、jstack)。
- dump 以及分析堆转储快照(jmap、jhat)。
- 方法级的程序运行性能分析,找到被调用最多、运行时间最长的方法。
- 离线程序快照:收集程序的运行时配置、线程 dump、内存 dump 等信息建立一个快照,可以将快照发送开发者处进行 Bug 反馈。
- 其他 plugins 的无限的可能性......
这里就不具体介绍 VisualVM 的使用,如果想了解的话可以看: