除了剛剛介紹 JDK 上豐富的命令列工具外, 還有兩個功能強大的視覺化工具 : JConsole 和 VisualVM. 其中 JConsole 在 JDK 1.5 就已經提供的 JVM 監控工具, 而 VisualVM 是在 JDK 1.6 Update7 中才首次發布, 現在已經成為主力推動的多合一故障處理工具, 並且已經從 JDK 中分離出來成為可以獨立開發的開放原始碼專案.
JConsole - Java 監視與管理主控台 :
JConsole (Java Monitoring and Management Console) 是一款基於 JMX 的視覺化監視與管理工具.
- 啟動 JConsole
透過 JDK/bin 目錄下的 "jconsole.exe" 啟動 JConsole 後, 將自動搜尋出本機執行的所有 JVM 進程 (透過 jps), 如下圖所示, 你可以選擇其中一個進程開始進行監控 :
選擇一個 LVM 進程後, 雙點擊可以進入管理介面 :
- 記憶體監控
"Memory" 頁籤相當於視覺化的 jstat 命令, 用於監視收集器管理的 JVM 記憶體 (Java Heap 與 永久代) 的變化趨勢. 我們可以使用下面代碼並執行來體驗一下它的監視功能 :
- package ch04;
- import java.util.ArrayList;
- import java.util.List;
- public class Ex4_6 {
- static class OOMObject{
- public byte[] placeholder = new byte[64*1024];
- }
- public static void fillHeap(int num) throws InterruptedException
- {
- List
list = new ArrayList (); - for(int i=0; i
- {
- Thread.sleep(50);
- list.add(new OOMObject());
- }
- System.gc();
- Thread.sleep(2000);
- }
- /**
- * Goal : 以 64KB/50ms 速度往 Java Heap 填充資料, 共填充 1000 次.
- * VM Args : -Xms100M -Xmx100M -XX:+UseSerialGC
- * @param args
- */
- public static void main(String[] args) throws Exception{
- fillHeap(1000);
- Thread.sleep(10000);
- }
- }
- Threads 監控
"Threads" 標籤功能相當於視覺化的 "jstack" 命令, 遇到 Threads 停頓時候可以使用這個功能進行監控分析. 前面講解 jstack 命令有提到過 Thread 長時間停頓原因主要有 : 等待外部資源, 閉環, 鎖等待. 透過下面代碼分別展示一下這幾種狀況 :
- package ch04;
- import java.io.BufferedReader;
- import java.io.InputStreamReader;
- public class Ex4_7 {
- public static void createBusyThread()
- {
- Thread thread = new Thread(new Runnable(){
- @Override
- public void run()
- {
- while(true); // 閉環.
- }
- }, "testBusyThread");
- thread.start();
- }
- public static void createLockThread(final Object lock)
- {
- Thread thread = new Thread(new Runnable(){
- @Override
- public void run()
- {
- synchronized(lock)
- {
- try
- {
- lock.wait(); // 鎖等待
- }
- catch(InterruptedException e){e.printStackTrace();}
- }
- }
- }, "testLockThread");
- thread.start();
- }
- /**
- * Goal : 展示 Thread 停頓原因 - 閉環, 鎖等待.
- * @param args
- */
- public static void main(String[] args) throws Exception{
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- br.readLine();
- createBusyThread();
- br.readLine();
- Object obj = new Object();
- createLockThread(obj);
- }
- }
接著在執行 Console 下任意輸入一鍵讓程式往下走, 接著監控 testBusyThread 線程, 如下圖所示, testBusyThread 一直在執行空循環, 從堆疊追蹤中可以看到該線程一直停留在程式碼第 13 行的位置 (while(true)). 這時候線程為 Runnable 狀態, 而沒有歸還執行權杖的動作, 會在空循環上用盡全部的執行時間直到線程切換, 這種等待會耗費較多的 CPU 資源 :
接著在執行 Console 下任意輸入一鍵讓程式往下走, 接著監控 testLockThread 線程. 下圖顯示線程在等待 lock 物件的 notify 或 notifyAll 方法的出現, 線程此時處在 WAITING 狀態, 在被喚醒前不會被分配執行時間 :
testLockThread 線程處於正常的活鎖狀態, 只要 lock 對象的 notify() 或 notifyAll() 方法被呼叫, 這個 線程 便能啟動並繼續執行. 在 JDK 命令列工具 有一個死鎖範例, 執行後再用 JConsole 監控 :
可以發現線程 Thread-1, Thread-2 處於 Block 狀態, 接著點擊 "Detect Deadlock" 可以檢查已經死鎖的線程 :
VisualVM - 多合一故障處理工具 :
VisualVM (All-in-One Java Troubleshooting Tool) 是目前為止隨 JDK 發布的功能最強大的執行監控與故障處理工具. "All-in-One" 意味它除了執行監控, 故障處理外, 還提供了很多其他 面的功能. 如性能分析(Profiling). 而且 VisualVM 還有一個很大的優點 : 不需要被監視的程式基於特殊 Agent 執行, 因此它對應用程式的實際性能影響很小, 使得它可以直接執行在應用環境中.
- 下載執行
VisualVM 在較新的 JDK 已經不隨之分布, 如果要使用需要自行下載, 下載後解壓縮可以在 bin 目錄下找到 "visualvm.exe", 執行後經過初始設定可以進入到下面的 GUI 介面 (我使用版本為 1.3.4):
- 分析程式性能
VisualVM 在 JDK 1.6 update7 中才首次出現, 但不意味它只能使用在 JDK 1.6 上的程式, 它具備很強向下相容能力, 這對無數已經處於維護狀態的老專案很有意義. 當然並非所有功能都能完美向下相容, 主要特性的相容性如下表所示 :
在開啟 VisualVM 後, 可以在左邊的 Applications 面板找到要監測的 JVM 進程 : (底下對 LVMID=7640 進行監測)
接著可以在右方面板點擊 "Sampler" 頁籤, 檢視 CPU 與 記憶體的使用狀況 :
(CPU Usage)
(Memory Usage)
沒有留言:
張貼留言