JDK 監(jiān)控和故障處理工具總結(jié)
JDK 命令行工具
這些命令在 JDK 安裝目錄下的 bin 目錄下:
-
jps
(JVM Process Status): 類似 UNIX 的ps
命令磨澡。用戶查看所有 Java 進(jìn)程的啟動(dòng)類、傳入?yún)?shù)和 Java 虛擬機(jī)參數(shù)等信息号涯; -
jstat
( JVM Statistics Monitoring Tool): 用于收集 HotSpot 虛擬機(jī)各方面的運(yùn)行數(shù)據(jù); -
jinfo
(Configuration Info for Java) : Configuration Info forJava,顯示虛擬機(jī)配置信息; -
jmap
(Memory Map for Java) :生成堆轉(zhuǎn)儲(chǔ)快照; -
jhat
(JVM Heap Dump Browser ) : 用于分析 heapdump 文件亏掀,它會(huì)建立一個(gè) HTTP/HTML 服務(wù)器一膨,讓用戶可以在瀏覽器上查看分析結(jié)果; -
jstack
(Stack Trace for Java):生成虛擬機(jī)當(dāng)前時(shí)刻的線程快照,線程快照就是當(dāng)前虛擬機(jī)內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合。
jps
:查看所有 Java 進(jìn)程
jps
(JVM Process Status) 命令類似 UNIX 的 ps
命令解藻。
jps
:顯示虛擬機(jī)執(zhí)行主類名稱以及這些進(jìn)程的本地虛擬機(jī)唯一 ID(Local Virtual Machine Identifier,LVMID)。jps -q
:只輸出進(jìn)程的本地虛擬機(jī)唯一 ID进倍。
C:\Users\SnailClimb>jps
7360 NettyClient2
17396
7972 Launcher
16504 Jps
17340 NettyServer
jps -l
:輸出主類的全名土至,如果進(jìn)程執(zhí)行的是 Jar 包,輸出 Jar 路徑猾昆。
C:\Users\SnailClimb>jps -l
7360 firstNettyDemo.NettyClient2
17396
7972 org.jetbrains.jps.cmdline.Launcher
16492 sun.tools.jps.Jps
17340 firstNettyDemo.NettyServer
jps -v
:輸出虛擬機(jī)進(jìn)程啟動(dòng)時(shí) JVM 參數(shù)陶因。
jps -m
:輸出傳遞給 Java 進(jìn)程 main() 函數(shù)的參數(shù)。
jstat
: 監(jiān)視虛擬機(jī)各種運(yùn)行狀態(tài)信息
jstat(JVM Statistics Monitoring Tool) 使用于監(jiān)視虛擬機(jī)各種運(yùn)行狀態(tài)信息的命令行工具垂蜗。 它可以顯示本地或者遠(yuǎn)程(需要遠(yuǎn)程主機(jī)提供 RMI 支持)虛擬機(jī)進(jìn)程中的類信息楷扬、內(nèi)存、垃圾收集贴见、JIT 編譯等運(yùn)行數(shù)據(jù)烘苹,在沒有 GUI,只提供了純文本控制臺(tái)環(huán)境的服務(wù)器上片部,它將是運(yùn)行期間定位虛擬機(jī)性能問題的首選工具镣衡。
jstat
命令使用格式:
jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
比如 jstat -gc -h3 31736 1000 10
表示分析進(jìn)程 id 為 31736 的 gc 情況,每隔 1000ms 打印一次記錄档悠,打印 10 次停止廊鸥,每 3 行后打印指標(biāo)頭部。
常見的 option 如下:
-
jstat -class vmid
:顯示 ClassLoader 的相關(guān)信息辖所; -
jstat -compiler vmid
:顯示 JIT 編譯的相關(guān)信息惰说; -
jstat -gc vmid
:顯示與 GC 相關(guān)的堆信息; -
jstat -gccapacity vmid
:顯示各個(gè)代的容量及使用情況缘回; -
jstat -gcnew vmid
:顯示新生代信息吆视; -
jstat -gcnewcapcacity vmid
:顯示新生代大小與使用情況; -
jstat -gcold vmid
:顯示老年代和永久代的信息切诀; -
jstat -gcoldcapacity vmid
:顯示老年代的大锌贰; -
jstat -gcpermcapacity vmid
:顯示永久代大蟹恰丰滑; -
jstat -gcutil vmid
:顯示垃圾收集信息;
另外倒庵,加上 -t
參數(shù)可以在輸出信息上加一個(gè) Timestamp 列褒墨,顯示程序的運(yùn)行時(shí)間。
jinfo
: 實(shí)時(shí)地查看和調(diào)整虛擬機(jī)各項(xiàng)參數(shù)
jinfo vmid
:輸出當(dāng)前 jvm 進(jìn)程的全部參數(shù)和系統(tǒng)屬性 (第一部分是系統(tǒng)的屬性擎宝,第二部分是 JVM 的參數(shù))郁妈。
jinfo -flag name vmid
:輸出對(duì)應(yīng)名稱的參數(shù)的具體值。比如輸出 MaxHeapSize绍申、查看當(dāng)前 jvm 進(jìn)程是否開啟打印 GC 日志 ( -XX:PrintGCDetails
:詳細(xì) GC 日志模式噩咪,這兩個(gè)都是默認(rèn)關(guān)閉的)顾彰。
C:\Users\SnailClimb>jinfo -flag MaxHeapSize 17340
-XX:MaxHeapSize=2124414976
C:\Users\SnailClimb>jinfo -flag PrintGC 17340
-XX:-PrintGC
使用 jinfo 可以在不重啟虛擬機(jī)的情況下,可以動(dòng)態(tài)的修改 jvm 的參數(shù)胃碾。尤其在線上的環(huán)境特別有用,請(qǐng)看下面的例子:
jinfo -flag [+|-]name vmid
開啟或者關(guān)閉對(duì)應(yīng)名稱的參數(shù)涨享。
C:\Users\SnailClimb>jinfo -flag PrintGC 17340
-XX:-PrintGC
C:\Users\SnailClimb>jinfo -flag +PrintGC 17340
C:\Users\SnailClimb>jinfo -flag PrintGC 17340
-XX:+PrintGC
jmap
:生成堆轉(zhuǎn)儲(chǔ)快照
jmap
(Memory Map for Java)命令用于生成堆轉(zhuǎn)儲(chǔ)快照。 如果不使用 jmap
命令仆百,要想獲取 Java 堆轉(zhuǎn)儲(chǔ)厕隧,可以使用 “-XX:+HeapDumpOnOutOfMemoryError”
參數(shù),可以讓虛擬機(jī)在 OOM 異常出現(xiàn)之后自動(dòng)生成 dump 文件俄周,Linux 命令下可以通過(guò) kill -3
發(fā)送進(jìn)程退出信號(hào)也能拿到 dump 文件吁讨。
jmap
的作用并不僅僅是為了獲取 dump 文件,它還可以查詢 finalizer 執(zhí)行隊(duì)列峦朗、Java 堆和永久代的詳細(xì)信息建丧,如空間使用率、當(dāng)前使用的是哪種收集器等甚垦。和jinfo
一樣茶鹃,jmap
有不少功能在 Windows 平臺(tái)下也是受限制的。
示例:將指定應(yīng)用程序的堆快照輸出到桌面艰亮。后面,可以通過(guò) jhat挣郭、Visual VM 等工具分析該堆文件迄埃。
C:\Users\SnailClimb>jmap -dump:format=b,file=C:\Users\SnailClimb\Desktop\heap.hprof 17340
Dumping heap to C:\Users\SnailClimb\Desktop\heap.hprof ...
Heap dump file created
jhat
: 分析 heapdump 文件
jhat
用于分析 heapdump 文件,它會(huì)建立一個(gè) HTTP/HTML 服務(wù)器兑障,讓用戶可以在瀏覽器上查看分析結(jié)果侄非。
C:\Users\SnailClimb>jhat C:\Users\SnailClimb\Desktop\heap.hprof
Reading from C:\Users\SnailClimb\Desktop\heap.hprof...
Dump file created Sat May 04 12:30:31 CST 2019
Snapshot read, resolving...
Resolving 131419 objects...
Chasing references, expect 26 dots..........................
Eliminating duplicate references..........................
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.
jstack
:生成虛擬機(jī)當(dāng)前時(shí)刻的線程快照
jstack
(Stack Trace for Java)命令用于生成虛擬機(jī)當(dāng)前時(shí)刻的線程快照。線程快照就是當(dāng)前虛擬機(jī)內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合.
生成線程快照的目的主要是定位線程長(zhǎng)時(shí)間出現(xiàn)停頓的原因流译,如線程間死鎖逞怨、死循環(huán)、請(qǐng)求外部資源導(dǎo)致的長(zhǎng)時(shí)間等待等都是導(dǎo)致線程長(zhǎng)時(shí)間停頓的原因福澡。線程出現(xiàn)停頓的時(shí)候通過(guò)jstack
來(lái)查看各個(gè)線程的調(diào)用堆棧叠赦,就可以知道沒有響應(yīng)的線程到底在后臺(tái)做些什么事情,或者在等待些什么資源革砸。
下面是一個(gè)線程死鎖的代碼除秀。我們下面會(huì)通過(guò) jstack
命令進(jìn)行死鎖檢查,輸出死鎖信息算利,找到發(fā)生死鎖的線程册踩。
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();
}
}
Output
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 通過(guò) synchronized (resource1) 獲得 resource1 的監(jiān)視器鎖,然后通過(guò)Thread.sleep(1000);
讓線程 A 休眠 1s 為的是讓線程 B 得到執(zhí)行然后獲取到 resource2 的監(jiān)視器鎖效拭。線程 A 和線程 B 休眠結(jié)束了都開始企圖請(qǐng)求獲取對(duì)方的資源暂吉,然后這兩個(gè)線程就會(huì)陷入互相等待的狀態(tài)胖秒,這也就產(chǎn)生了死鎖。
通過(guò) jstack
命令分析:
C:\Users\SnailClimb>jps
13792 KotlinCompileDaemon
7360 NettyClient2
17396
7972 Launcher
8932 Launcher
9256 DeadLockDemo
10764 Jps
17340 NettyServer
C:\Users\SnailClimb>jstack 9256
輸出的部分內(nèi)容如下:
Found one Java-level deadlock:
=============================
"線程 2":
waiting to lock monitor 0x000000000333e668 (object 0x00000000d5efe1c0, a java.lang.Object),
which is held by "線程 1"
"線程 1":
waiting to lock monitor 0x000000000333be88 (object 0x00000000d5efe1d0, 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:31)
- waiting to lock <0x00000000d5efe1c0> (a java.lang.Object)
- locked <0x00000000d5efe1d0> (a java.lang.Object)
at DeadLockDemo$$Lambda$2/1078694789.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
"線程 1":
at DeadLockDemo.lambda$main$0(DeadLockDemo.java:16)
- waiting to lock <0x00000000d5efe1d0> (a java.lang.Object)
- locked <0x00000000d5efe1c0> (a java.lang.Object)
at DeadLockDemo$$Lambda$1/1324119927.run(Unknown Source)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
可以看到 jstack
命令已經(jīng)幫我們找到發(fā)生死鎖的線程的具體信息慕的。
JDK 可視化分析工具
JConsole:Java 監(jiān)視與管理控制臺(tái)
JConsole 是基于 JMX 的可視化監(jiān)視阎肝、管理工具∫导冢可以很方便的監(jiān)視本地及遠(yuǎn)程服務(wù)器的 java 進(jìn)程的內(nèi)存使用情況盗痒。你可以在控制臺(tái)輸出console
命令啟動(dòng)或者在 JDK 目錄下的 bin 目錄找到jconsole.exe
然后雙擊啟動(dòng)。
連接 Jconsole
如果需要使用 JConsole 連接遠(yuǎn)程進(jìn)程低散,可以在遠(yuǎn)程 Java 程序啟動(dòng)時(shí)加上下面這些參數(shù):
-Djava.rmi.server.hostname=外網(wǎng)訪問 ip 地址
-Dcom.sun.management.jmxremote.port=60001 //監(jiān)控的端口號(hào)
-Dcom.sun.management.jmxremote.authenticate=false //關(guān)閉認(rèn)證
-Dcom.sun.management.jmxremote.ssl=false
在使用 JConsole 連接時(shí)俯邓,遠(yuǎn)程進(jìn)程地址如下:
外網(wǎng)訪問 ip 地址:60001
查看 Java 程序概況
內(nèi)存監(jiān)控
JConsole 可以顯示當(dāng)前內(nèi)存的詳細(xì)信息。不僅包括堆內(nèi)存/非堆內(nèi)存的整體信息熔号,還可以細(xì)化到 eden 區(qū)稽鞭、survivor 區(qū)等的使用情況,如下圖所示引镊。
點(diǎn)擊右邊的“執(zhí)行 GC(G)”按鈕可以強(qiáng)制應(yīng)用程序執(zhí)行一個(gè) Full GC朦蕴。
- 新生代 GC(Minor GC):指發(fā)生新生代的的垃圾收集動(dòng)作,Minor GC 非常頻繁弟头,回收速度一般也比較快吩抓。
- 老年代 GC(Major GC/Full GC):指發(fā)生在老年代的 GC,出現(xiàn)了 Major GC 經(jīng)常會(huì)伴隨至少一次的 Minor GC(并非絕對(duì))赴恨,Major GC 的速度一般會(huì)比 Minor GC 的慢 10 倍以上疹娶。
線程監(jiān)控
類似我們前面講的 jstack
命令,不過(guò)這個(gè)是可視化的伦连。
最下面有一個(gè)"檢測(cè)死鎖 (D)"按鈕雨饺,點(diǎn)擊這個(gè)按鈕可以自動(dòng)為你找到發(fā)生死鎖的線程以及它們的詳細(xì)信息 。
Visual VM:多合一故障處理工具
VisualVM 提供在 Java 虛擬機(jī) (Java Virutal Machine, JVM) 上運(yùn)行的 Java 應(yīng)用程序的詳細(xì)信息惑淳。在 VisualVM 的圖形用戶界面中额港,您可以方便、快捷地查看多個(gè) Java 應(yīng)用程序的相關(guān)信息歧焦。Visual VM 官網(wǎng):https://visualvm.github.io/ 移斩。Visual VM 中文文檔:https://visualvm.github.io/documentation.html。
下面這段話摘自《深入理解 Java 虛擬機(jī)》倚舀。
VisualVM(All-in-One Java Troubleshooting Tool)是到目前為止隨 JDK 發(fā)布的功能最強(qiáng)大的運(yùn)行監(jiān)視和故障處理程序叹哭,官方在 VisualVM 的軟件說(shuō)明中寫上了“All-in-One”的描述字樣,預(yù)示著他除了運(yùn)行監(jiān)視痕貌、故障處理外风罩,還提供了很多其他方面的功能,如性能分析(Profiling)舵稠。VisualVM 的性能分析功能甚至比起 JProfiler超升、YourKit 等專業(yè)且收費(fèi)的 Profiling 工具都不會(huì)遜色多少入宦,而且 VisualVM 還有一個(gè)很大的優(yōu)點(diǎn):不需要被監(jiān)視的程序基于特殊 Agent 運(yùn)行,因此他對(duì)應(yīng)用程序的實(shí)際性能的影響很小室琢,使得他可以直接應(yīng)用在生產(chǎn)環(huán)境中乾闰。這個(gè)優(yōu)點(diǎn)是 JProfiler、YourKit 等工具無(wú)法與之媲美的盈滴。
VisualVM 基于 NetBeans 平臺(tái)開發(fā)涯肩,因此他一開始就具備了插件擴(kuò)展功能的特性,通過(guò)插件擴(kuò)展支持巢钓,VisualVM 可以做到:
- 顯示虛擬機(jī)進(jìn)程以及進(jìn)程的配置病苗、環(huán)境信息(jps、jinfo)症汹。
- 監(jiān)視應(yīng)用程序的 CPU硫朦、GC、堆背镇、方法區(qū)以及線程的信息(jstat咬展、jstack)。
- dump 以及分析堆轉(zhuǎn)儲(chǔ)快照(jmap瞒斩、jhat)破婆。
- 方法級(jí)的程序運(yùn)行性能分析,找到被調(diào)用最多胸囱、運(yùn)行時(shí)間最長(zhǎng)的方法荠割。
- 離線程序快照:收集程序的運(yùn)行時(shí)配置、線程 dump旺矾、內(nèi)存 dump 等信息建立一個(gè)快照,可以將快照發(fā)送開發(fā)者處進(jìn)行 Bug 反饋夺克。
- 其他 plugins 的無(wú)限的可能性......