首先,JDK 自帶了很多監控工具,都位于 JDK 的 bin 目錄下,其中最常用的是 jconsole 和 jvisualvm 這兩款視圖監控工具。
一、jps(Java Process Status)
用于查看有權訪問的虛擬機的進程,并顯示他們的進程號
-v:列出虛擬機進程啟動時的 JVM 參數。比如:-Xms20m -Xmx50m 是啟動程序指定的 jvm 參數
二、jstat(JVM Statistics Monitoring Tool)
可以用來監視 JVM 內存內的各種堆和非堆的大小及其內存使用量、類裝載、垃圾收集、JIT 編譯等運行數據
jstat - [-t] [-h] [ []]
-gc:顯示堆各分區大小、YGC,FGC次數和時長。包括 Eden 區、兩個 Survivor 區、老年代、永久代等的容量、已用空間、GC 時間合計等信息
-gccapacity:顯示內容與 -gc 基本相同,但輸出主要關注 Java 堆各個區域使用到的最大、最小空間
-gcutil:顯示內容與 -gc 基本相同,但輸出主要關注已使用空間占總空間的百分比
-gccause:與 -gcutil 功能一樣,但是會額外輸出導致最后一次或當前正在發生的 GC 產生的原因
-gcnew:顯示新生代 GC 狀況
-gcnewcapacity:顯示內容與 -gcnew 基本相同,輸出主要關注使用到的最大、最小空間
-geold:顯示老年代 GC 狀況
-gcoldcapacity:顯示內容與 -gcold 基本相同,輸出主要關注使用到的最大、最小空間
-gcpermcapacity:顯示永久代使用到的最大、最小空間
interval 參數:用于指定輸出統計數據的周期,單位為毫秒。即:查詢間隔
count 參數:用于指定查詢的總次數
OOM案例:比較GC時長(GCT列)占運行市場的比例:
如果該比例超過 20%,則說明目前堆的壓力較大;
如果該比例超過 98%,則說明這段時期內幾乎一直在GC,堆里幾乎沒有可用空間,隨時都可能拋出 OOM 異常
內存泄露案例
每隔一段較長的時間采樣多組 OU(老年代內存量) 的最小值,如果這些最小值在上漲,說明無法回收對象在不斷增加,可能是內存泄漏導致的。
在長時間運行的 Java 程序中,我們可以運行 jstat 命令連續獲取多行性能數據,并取這幾行數據中 OU 列(Old Used,已占用的老年代內存)的最小值
然后,我們每隔一段較長的時間重復一次上述操作,來獲得多組 OU 最小值。
如果這些值呈上漲趨勢,則說明該 Java 程序的老年代內存已使用量在不斷上漲,這意味著無法回收的對象在不斷增加,因此很有可能存在內存泄漏(不再使用的對象仍然被引用,導致GC無法回收)
三、jstack(JVM Stack Trace)
用于生成虛擬機指定進程當前時刻的線程快照(虛擬機堆棧跟蹤)
參數:
-F 當正常輸出的請求不被響應時,強制輸出線程堆棧
-l 除堆棧外,顯示關于鎖的附加信息
線程快照:該進程內每條線程正在執行的方法堆棧的集合。
生成線程快照的作用:可用于定位線程出現長時間停頓的原因,如線程間死鎖、死循環、請求外部資源導致的長時間等待等問題。
這些都是導致線程長時間停頓的常見原因。當線程出現停頓時,就可以用 jstack 顯示各個線程調用的堆棧情況。
在 thread dump 中,要留意下面幾種狀態
- 死鎖,Deadlock(重點關注)
- 等待資源,Waiting on condition(重點關注)
- 等待獲取監視器,Waiting on monitor entry(重點關注)
- 阻塞,Blocked(重點關注)
- 執行中,Runnable
- 暫停,Suspended
- 對象等待中,Object.wait() 或 TIMED_WAITING
- 停止,Parked
四、jmap(Memory Map)和jhat(Java Heap Analysis Tool)
jmap:打印出某個 JVM 進程內存內的所有對象的情況,一般用于查看內存占用情況。一般結合jhat使用
使用jmap -histo[:live] pid查看堆內存中的對象數目、大小統計直方圖,如果帶上live則只統計活對象,
jmap進行dump命令格式 jmap -dump:format=b,file=dumpFileName pid
五、Visual VM
六、jconsole:
一個 GUI 監視工具,可以以圖表化的形式顯示各種數據,并支持遠程連接