第1部分:JDK命令行工具
这些命令在 JDK 安装目录下的 bin 目录下:
- jps (JVM Process Status):类似 UNIX 的 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):生成虚拟机当前时刻的线程快照,线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合。
1.1
jps
:查看所有Java进程jps (JVM Process Status)命令类似 UNIX 的 ps 命令。
jps:显示虚拟机执行主类名称以及这些进程的本地虚拟机唯一 ID(Local Virtual Machine Identifier,LVMID)。jps -q :只输出进程的本地虚拟机唯一 ID。C:\Users\Mr. X>jps
12512 spring
18800 Jps
1688 Launcher
4300
jps -l:输出主类的全名,如果进程执行的是 Jar 包,输出 Jar 路径。
C:\Users\Mr. X>jps -l
12512 D:\developer_tools\spring
896 sun.tools.jps.Jps
22740 org.jetbrains.jps.cmdline.Launcher
15916 com.ruoyi.RuoYiApplication
23564 org.jetbrains.jps.cmdline.Launcher
4300
jps -v:输出虚拟机进程启动时 JVM 参数。
C:\Users\Mr. X>jps -v
12512 spring -Dnacos.standalone=true -Xbootclasspath/a:D:\developer_tools\spring cloud\nacos\plugins\cmdb:D:\developer_tools\spring cloud\nacos\plugins\mysql -Dnacos.home=D:\developer_tools\spring cloud\nacos -Dloader.path=D:\developer_tools\spring cloud\nacos/plugins/health
22740 Launcher -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Djdt.compiler.useSingleThread=true -Dpreload.project.path=D:/workspace_idea/LeetcodeTest -Dpreload.config.path=C:/Users/Mr. X/AppData/Roaming/JetBrains/IntelliJIdea2021.1/options -Dcompile.parallel=false -Drebuild.on.dependency.change=true -Dio.netty.initialSeedUniquifier=-2910994808669652962 -Dfile.encoding=GBK -Duser.language=zh -Duser.country=CN -Didea.paths.selector=IntelliJIdea2021.1 -Didea.home.path=D:\developer_tools\IntelliJ IDEA 2021.1.2 -Didea.config.path=C:\Users\Mr. X\AppData\Roaming\JetBrains\IntelliJIdea2021.1 -Didea.plugins.path=C:\Users\Mr. X\AppData\Roaming\JetBrains\IntelliJIdea2021.1\plugins -Djps.log.dir=C:/Users/Mr. X/AppData/Local/JetBrains/IntelliJIdea2021.1/log/build-log -Djps.fallback.jdk.home=D:/developer_tools/IntelliJ IDEA 2021.1.2/jbr -Djps.fallback.jdk.version=11.0.11 -Dio.netty.noUnsafe=true -Djava.io.tmpdir=C:/Users/Mr. X/AppData/Local/JetBrains/IntelliJIdea2021.1/compile-server/leetcodetest_3f5b2da5/_temp_ -Djps.backwa
15916 RuoYiApplication -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -javaagent:D:\developer_tools\IntelliJ IDEA 2021.1.2\lib\idea_rt.jar=51262:D:\developer_tools\IntelliJ IDEA 2021.1.2\bin -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -Dfile.encoding=UTF-8
23564 Launcher -Xmx700m -Djava.awt.headless=true -Djava.endorsed.dirs="" -Djdt.compiler.useSingleThread=true -Dpreload.project.path=D:/workspace_idea/wechat-alarm-server -Dpreload.config.path=C:/Users/Mr. X/AppData/Roaming/JetBrains/IntelliJIdea2021.1/options -Dcompile.parallel=false -Drebuild.on.dependency.change=true -Dio.netty.initialSeedUniquifier=-2910994808669652962 -Dfile.encoding=GBK -Duser.language=zh -Duser.country=CN -Didea.paths.selector=IntelliJIdea2021.1 -Didea.home.path=D:\developer_tools\IntelliJ IDEA 2021.1.2 -Didea.config.path=C:\Users\Mr. X\AppData\Roaming\JetBrains\IntelliJIdea2021.1 -Didea.plugins.path=C:\Users\Mr. X\AppData\Roaming\JetBrains\IntelliJIdea2021.1\plugins -Djps.log.dir=C:/Users/Mr. X/AppData/Local/JetBrains/IntelliJIdea2021.1/log/build-log -Djps.fallback.jdk.home=D:/developer_tools/IntelliJ IDEA 2021.1.2/jbr -Djps.fallback.jdk.version=11.0.11 -Dio.netty.noUnsafe=true -Djava.io.tmpdir=C:/Users/Mr. X/AppData/Local/JetBrains/IntelliJIdea2021.1/compile-server/wechat-alarm-server_541fcf3a/_temp
3132 Jps -Dapplication.home=D:\developer_tools\Java\jdk1.8.0_291 -Xms8m
4300 exit -Xms128m -Xmx2026m -XX:ReservedCodeCacheSize=512m -XX:+UseG1GC -XX:SoftRefLRUPolicyMSPerMB=50 -XX:CICompilerCount=2 -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -ea -Dsun.io.useCanonCaches=false -Djdk.http.auth.tunneling.disabledSchemes="" -Djdk.attach.allowAttachSelf=true -Djdk.module.illegalAccess.silent=true -Dkotlinx.coroutines.debug=off -Djb.vmOptionsFile=C:\Users\Mr. X\AppData\Roaming\JetBrains\IntelliJIdea2021.1\idea64.exe.vmoptions -Didea.jre.check=true -Dide.native.launcher=true -Didea.vendor.name=JetBrains -Didea.paths.selector=IntelliJIdea2021.1 -XX:ErrorFile=C:\Users\Mr. X\java_error_in_idea64_%p.log -XX:HeapDumpPath=C:\Users\Mr. X\java_error_in_idea64.hprof
jps -m:输出传递给 Java 进程 main() 函数的参数。
C:\Users\Mr. X>jps -m
12512 spring cloud\nacos\target\nacos-server.jar --spring.config.location=classpath:/,classpath:/config/,file:./,file:./config/,file:D:\developer_tools\spring cloud\nacos/conf/ --logging.config=D:\developer_tools\spring cloud\nacos/conf/nacos-logback.xml nacos.nacos
22740 Launcher D:/developer_tools/IntelliJ IDEA 2021.1.2/plugins/java/lib/jps-builders-6.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/netty-buffer.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/guava.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/jna.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/plexus-utils-3.3.0.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/forms_rt.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/plugins/java/lib/maven-resolver-transport-http-1.3.3.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/jna-platform.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/commons-lang3-3.10.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/nanoxml-2.2.3.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/platform-api.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/slf4j.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/log4j.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/plugins/java/lib/maven-resolver-transport-file-1.3.3.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2
17880 Jps -m
15916 RuoYiApplication
23564 Launcher D:/developer_tools/IntelliJ IDEA 2021.1.2/plugins/java/lib/jps-builders-6.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/netty-buffer.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/guava.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/jna.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/plexus-utils-3.3.0.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/forms_rt.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/plugins/java/lib/maven-resolver-transport-http-1.3.3.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/jna-platform.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/commons-lang3-3.10.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/nanoxml-2.2.3.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/platform-api.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/slf4j.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/lib/log4j.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2/plugins/java/lib/maven-resolver-transport-file-1.3.3.jar;D:/developer_tools/IntelliJ IDEA 2021.1.2
4300
1.2
jstat
:监视虚拟机各种运行状态信息jstat(JVM Statistics Monitoring Tool)使用于监视虚拟机各种运行状态信息的命令行工具。 它可以显示本地或者远程(需要远程主机提供 RMI 支持)虚拟机进程中的类信息、内存、垃圾收集、JIT 编译等运行数据,在没有 GUI,只提供了纯文本控制台环境的服务器上,它将是运行期间定位虚拟机性能问题的首选工具。
jstat 命令使用格式:jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
比如 jstat -gc -h3 31736 1000 10表示分析进程 id 为 31736 的 gc 情况,每隔 1000ms 打印一次记录,打印 10 次停止,每 3 行后打印指标头部。
常见的 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 :显示老年代和永久代的行为统计,从jdk1.8开始,该选项仅表示老年代,因为永久代被移除了;
- jstat -gcoldcapacity vmid :显示老年代的大小;
- jstat -gcpermcapacity vmid :显示永久代大小,从jdk1.8开始,该选项不存在了,因为永久代被移除了;
- jstat -gcutil vmid:显示垃圾收集信息;
另外,加上 -t参数可以在输出信息上加一个 Timestamp 列,显示程序的运行时间。
1.3 jinfo
:实时查看和调整虚拟机各项参数
- jinfo vmid:输出当前 jvm 进程的全部参数和系统属性 (第一部分是系统的属性,第二部分是 JVM 的参数)。
jinfo -flag name vmid:输出对应名称的参数的具体值。比如输出 MaxHeapSize、查看当前 jvm 进程是否开启打印 GC 日志 ( -XX:PrintGCDetails:详细 GC 日志模式,这两个都是默认关闭的)。
C:\Users\Mr. X>jinfo -flag MaxHeapSize 15916
-XX:MaxHeapSize=4250927104
使用 jinfo 可以在不重启虚拟机的情况下,可以动态的修改 jvm 的参数。尤其在线上的环境特别有用,请看下面的例子:
jinfo -flag [+|-]name vmid 开启或者关闭对应名称的参数。 ```powershell C:\Users\Mr. X>jinfo -flag PrintGC 15916 -XX:-PrintGC
C:\Users\Mr. X>jinfo -flag +PrintGC 15916
C:\Users\Mr. X>jinfo -flag PrintGC 15916 -XX:+PrintGC
<a name="h0SsM"></a>
## 1.4 `jmap`:生成堆转储快照
jmap (Memory Map for Java) 命令用于生成堆转储快照。如果不使用 jmap 命令,要想获取 Java 堆转储,可以使用 “-XX:+HeapDumpOnOutOfMemoryError” 参数,可以让虚拟机在 OOM 异常出现之后自动生成 dump 文件,Linux 命令下可以通过 kill -3 发送进程退出信号也能拿到 dump 文件。<br />jmap 的作用并不仅仅是为了获取 dump 文件,它还可以查询 finalizer 执行队列、Java 堆和永久代的详细信息,如空间使用率、当前使用的是哪种收集器等。和 jinfo 一样,jmap有不少功能在 Windows 平台下也是受限制的。<br />示例:将指定应用程序的堆快照输出到指定目录。后面,可以通过 jhat、Visual VM 等工具分析该堆文件。
```powershell
C:\Users\Mr. X>jmap -dump:format=b,file=D:\heap.hprof 15916
Dumping heap to D:\heap.hprof ...
Heap dump file created
1.5 jhat
:分析headdump文件
jhat 用于分析 heapdump 文件,它会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果:
jhat D:\heap.hprof
Reading from D:\heap.hprof...
Dump file created Sat Jul 17 14:21:41 CST 2021
Snapshot read, resolving...
Resolving 824348 objects...
Chasing references, expect 164 dots....................................................................................................................................................................
Eliminating duplicate references....................................................................................................................................................................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
1.6 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 命令分析:
C:\Users\Mr. X>jps
12512 spring
19636 Jps
15916 RuoYiApplication
23564 Launcher
23900 DeadLockDemo
4300
524 Launcher
C:\Users\Mr. X>jstack 23900
2021-07-17 14:55:14
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.291-b10 mixed mode):
"DestroyJavaVM" #14 prio=5 os_prio=0 tid=0x0000022da6468000 nid=0x5ee4 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"线程 2" #13 prio=5 os_prio=0 tid=0x0000022dc31a9000 nid=0x433c waiting for monitor entry [0x00000046a5fff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at DeadLockDemo.lambda$main$1(DeadLockDemo.java:37)
- waiting to lock <0x000000076bb9d7d0> (a java.lang.Object)
- locked <0x000000076bb9d7e0> (a java.lang.Object)
at DeadLockDemo$$Lambda$2/558638686.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"线程 1" #12 prio=5 os_prio=0 tid=0x0000022dc31a4000 nid=0x680 waiting for monitor entry [0x00000046a5eff000]
java.lang.Thread.State: BLOCKED (on object monitor)
at DeadLockDemo.lambda$main$0(DeadLockDemo.java:22)
- waiting to lock <0x000000076bb9d7e0> (a java.lang.Object)
- locked <0x000000076bb9d7d0> (a java.lang.Object)
at DeadLockDemo$$Lambda$1/1831932724.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"Service Thread" #11 daemon prio=9 os_prio=0 tid=0x0000022dc2f0c000 nid=0x33bc runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread3" #10 daemon prio=9 os_prio=2 tid=0x0000022dc2e89800 nid=0x5e64 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread2" #9 daemon prio=9 os_prio=2 tid=0x0000022dc2e5a800 nid=0x3d9c waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #8 daemon prio=9 os_prio=2 tid=0x0000022dc2e56800 nid=0x5e8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #7 daemon prio=9 os_prio=2 tid=0x0000022dc2e52000 nid=0x43dc waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Monitor Ctrl-Break" #6 daemon prio=5 os_prio=0 tid=0x0000022dc10ec800 nid=0x9e4 runnable [0x00000046a57fe000]
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 <0x000000076ba8fb08> (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 <0x000000076ba8fb08> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:48)
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000022dc1077000 nid=0x4c50 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000022dc1076000 nid=0x2a54 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x0000022dc1048000 nid=0x2544 in Object.wait() [0x00000046a54fe000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076b908ee0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:144)
- locked <0x000000076b908ee0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:165)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:216)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000022dc1040800 nid=0x3a94 in Object.wait() [0x00000046a53ff000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x000000076b906c00> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:502)
at java.lang.ref.Reference.tryHandlePending(Reference.java:191)
- locked <0x000000076b906c00> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
"VM Thread" os_prio=2 tid=0x0000022dc1016800 nid=0x3180 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000022da647f800 nid=0x664 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000022da6481000 nid=0x2cf4 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x0000022da6482800 nid=0x3218 runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x0000022da6483800 nid=0x3de4 runnable
"GC task thread#4 (ParallelGC)" os_prio=0 tid=0x0000022da6485800 nid=0xd58 runnable
"GC task thread#5 (ParallelGC)" os_prio=0 tid=0x0000022da6487000 nid=0x5b64 runnable
"GC task thread#6 (ParallelGC)" os_prio=0 tid=0x0000022da648a000 nid=0x5b80 runnable
"GC task thread#7 (ParallelGC)" os_prio=0 tid=0x0000022da648b000 nid=0x513c runnable
"VM Periodic Task Thread" os_prio=2 tid=0x0000022dc2f3a800 nid=0x56cc waiting on condition
JNI global references: 317
Found one Java-level deadlock:
=============================
"线程 2":
waiting to lock monitor 0x0000022dc1045228 (object 0x000000076bb9d7d0, a java.lang.Object),
which is held by "线程 1"
"线程 1":
waiting to lock monitor 0x0000022dc1047ab8 (object 0x000000076bb9d7e0, a java.lang.Object),
which is held by "线程 2"
Java stack information for the threads listed above:
===================================================
"线程 2":
at DeadLockDemo.lambda$main$1(DeadLockDemo.java:37)
- waiting to lock <0x000000076bb9d7d0> (a java.lang.Object)
- locked <0x000000076bb9d7e0> (a java.lang.Object)
at DeadLockDemo$$Lambda$2/558638686.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"线程 1":
at DeadLockDemo.lambda$main$0(DeadLockDemo.java:22)
- waiting to lock <0x000000076bb9d7e0> (a java.lang.Object)
- locked <0x000000076bb9d7d0> (a java.lang.Object)
at DeadLockDemo$$Lambda$1/1831932724.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
第2部分:JDK可视化分析工具
2.1 JConsole:Java监视与管理控制台
JConsole 是基于 JMX 的可视化监视、管理工具。可以很方便的监视本地及远程服务器的 java 进程的内存使用情况。你可以在控制台输出console命令启动或者在 JDK 目录下的 bin 目录找到jconsole.exe然后双击启动。
连接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)”按钮,点击这个按钮可以自动为你找到发生死锁的线程以及它们的详细信息 。
:
2.2 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。
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 的无限的可能性……