您是否曾經遇到過沒有明確原因的應用程序服務器掛起或者 Java 應用程序變得沒有響應?您的應用程序是否內存不足 或者運行情況欠佳?使用 Health Center,您就可以更輕松地解決這些問題。
使用 Health Center 監視和診斷問題
Health Center 是一款適用於 Java 的 IBM 監視和診斷工具,是一個免費的低開銷診斷工具和 API,用於監視在 IBM Java 虛擬機 (JVM) 上運行的應用程序。借助 Health Center,您可以通過提供信息來快速評估正在運行的 Java 應用 程序的狀態,從而確定問題並幫助解決問題。您可以:
確定是否存在本機或堆內存洩露
發現哪些方法需要使用較長的運行時間
確定 I/O 瓶頸
使垃圾收集可視化並進行調優
查看所有鎖爭用
分析異常的 WebSphere Real Time 事件
監視應用程序的線程活動
檢測死鎖條件
收集類的直方圖數據
最新版本的 Health Center 是一個功能強大的全新 API,您可以使用它編寫自己的監視工具。令人煩惱的難於查找問題 的時代馬上就要結束了。
在本文中,我們將學習編寫一個用於檢查應用程序死鎖條件的監視工具,然後,應用這些 原則來編寫更深入的工具、查詢從垃圾收集活動到方法分析的所有問題,並確定應用程序將其 CPU 周期花費在了哪些地方 。
系統要求
Health Center API 包至少需要安裝 Eclipse 3.4 或 Eclipse 4.x。
將 API 程序包安 裝到 Eclipse 中
IBM 監視和診斷工具通常安裝在 IBM 支持助手 (ISA) 中,要將 Health Center 嵌入您的應用程 序並使用 API 對其進行編碼,首先需要將它安裝到您的 Eclipse 環境中。為此,請執行以下步驟:
啟動 Eclipse 開發環境。
轉到 Help -> Install New Software。
添加 ISA 更新網站作為一個新網站。
單擊 Add。
在名稱框中輸入 ISA Update 網站。
在位置框中輸入此 URL:http://public.dhe.ibm.com/software/isa/isa410/production/。該操作會啟動對所有可用 工具的搜索,該搜索可能需要花費幾分鐘的時間。
在搜索框中輸入 Health Center。
選擇程序包 Health Center Core Feature 並單擊 Next(參見圖 1):
圖 1. 將要安裝的可用軟件的列表
確認安裝細節並單擊 Next。
閱讀並接受許可條款,然後單擊 Finish。這些步驟會將 Health Center 核心功能安裝到您的 Eclipse IDE 中。您可 以准備好對此 API 進行編碼。
確認安裝細節並單擊 Next。
使用此 API 編寫一個簡單的 rcp 來檢測死鎖。首先,在 Eclipse 中創建一個新的插件項目並添加 Health Center API 作為一個依賴項。為此,請執行以下步驟:
轉到 File -> New -> Project -> Plug-in Project。
為該項目提供一個名稱,如 HC_Deadlock。單擊 Next。
清除 Generate an activator 復選框。當系統詢問您是否想創建一個富客戶端應用程序時,單擊 Yes。然後單擊 Next(參見圖 2):
圖 2. 插件項目選項
單擊 Next。在模板屏幕上,選擇 Headless Hello RCP。然後單擊 Finish。
接下來,將 Health Center API 程序包作為依賴項添加到這個新項目。請遵循以下步驟:
要將 API 導入添加到清單中,請打開新項目中 META-INF 下的 MANIFEST.MF 文件(參見圖 3):
圖 3. Package Explorer 插件
選擇Dependencies 選項卡並單擊 Add。在 Select a Plug-in 字段的搜索中鍵入 healthcenter.api。選擇 com.ibm.java.diagnostics.healthcenter.api 插件,請注意,版本號可能有所不同(參見圖 4):
圖 4. Health Center API 插件選擇
單擊 OK。重復 選擇 Dependencies 選項卡 步驟中的練習。這次,再次添加 org.eclipse.ui,版本號可能會有 所不同(參見圖 5):
圖 5. org.eclipse.ui 的插件選擇
單擊 OK,然後保存該文件。
此 API 插件現在已經包含在您的應用程序中,您可以開始對其進行編碼了。
測試死鎖應用程序
編 寫死鎖監視工具之前,您可能想監視某些內容。清單 1 顯示了一個獲取死鎖的簡單應用程序的源代碼:
清單 1. 一 個具有死鎖的簡單應用程序
public class GenerateDeadlock { AThread t1 = null; AThread t2 = null; AThread t3 = null; static class AThread extends Thread { Object hold; Object grab; AThread(String name, Object hold, Object grab) { super(name); this.hold = hold; this.grab = grab; } private void delay(long time) { try { Thread.sleep(time); } catch (InterruptedException e) { } } private void grabLocks() { System.out.println("Thread " + this + " about to hold " + hold); synchronized (hold) { System.out.println(" Thread " + this + " about to grab " + grab); delay(5000); synchronized (grab) { System.out.println(" Thread " + this + " got both monitors"); delay(1000000); } } } public void run() { System.out.println("Thread " + this + " starting"); for (int i = 0; i < 200000; i++) { grabLocks(); } System.out.println("Thread " + this + " completed"); } } private void createDeadlock() { System.out.println("Force 3 thread deadlock"); String s1 = "obj 1"; String s2 = "obj 2"; String s3 = "obj 3"; t1 = new AThread("Thread 1", s1, s2); t2 = new AThread("Thread 2", s2, s3); t3 = new AThread("Thread 3", s3, s1); t1.start(); t2.start(); t3.start(); } public static void main(String[] args) { GenerateDeadlock d = new GenerateDeadlock(); d.createDeadlock(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Press a key to exit"); try { System.in.read(); System.exit(0); } catch (java.io.IOException e) { } } }
Health Center 包含兩個部分,第一部分是 Health Center 代理,它與要監視的應用程序一起加載。該代理提 供了對 JVM 中數據的訪問,這就是隨後要使用的 Health Center 的第二部分,即客戶端。此 API 為您提供了訪問客戶端 的訪問權限,通常是從 ISA 開始。將此客戶端嵌入您的應用程序中,以便連接到使用 Health Center 代理啟動的應用程序 ,並獲得訪問 Health Center 客戶端監視和顯示的所有數據的權限。此 API 不提供 GUI,而是生成可在您自己的應用程序 中使用的所有數據。圖 6 概述了將 Health Center 客戶端和代理安裝到 ISA 和 JVM 中時它們所在的位置:
圖 6. Health Center 客戶端和代理安裝在 ISA 和 JVM 中時所在的位置
啟動 清單 1 中的程序及其連接的 Health Center 代理。它至少需要 IBM Java 級別的 Java 5 SR8、Java 6 SR1 或 Java 7。您可以下載 IBM 開發人員工具包。
要使用 Java 5 SR10 及其更高版本、Java 6 SR5 及更高版本和 Java 7 來啟動應用程序與代理,請使用以下命令 (參見圖 7):
java - Xhealthcenter GenerateDeadlock
對於 Java 5 SR9 及其早期版本或者 Java 6 SR4 及其早期版本,請使用以下命令:
java - agentlib:healthcenter - Xtrace:output=healthcenter.out GenerateDeadlock
圖 7. 運行 GenerateDeadlock 程序
Java 5 SR9 和 Java 6 SR3 自動包含此代理。有關最新版本的代理以及如何更新代理的說明,請訪問 Health Center - 安裝 Health Center 代理。
編寫死鎖監視應用程序代碼
現在,您可以使用 Health Center API 修改基本的 Hello RCP World 應用程序,並將其轉變成死鎖檢測工具。打開名為 Application.java 的文件(參見圖 8):
圖 8. Application.java 代碼的位置
設置連接詳細信息
首先,獲取一個 ConnectionProperties 對象,該對象包含您要連接的應用程序的詳細信息。默認的對象設置為使用 localhost 和端口 1972,但您可以在構造函數和類方法中更改這些值(和提高安全性):
ConnectionProperties hcConn = new ConnectionProperties();
在擁有 ConnectionProperties 對象時,可以連接到您要監視的應用程序,該應用程序已 經與 Health Center 代理一起啟動。調用靜態的 HealthCenterFactory.connect(hcConn, true) 方法。該調用返回一個 HealthCenter 對象,此對象直接連接到 Health Center 並且允許訪問 Health Center 監視的所有數據。此連接調用有效 地啟動了您的應用程序中的一個 Health Center 實例並開始收集數據:
HealthCenter hcMon = HealthCenterFactory.connect(hcConn,true);
獲取數據
在擁有 HealthCenter 對象之後,就可以開始查詢 數據。采用類似於 GUI的方式布置此 API:在獲取 HealthCenter 對象之後,此 API 的第一步操作就是調用您感興趣的數 據類型。對於此示例,我們希望檢查死鎖,它是 ThreadsData 類的一部分。您可以在 HealthCenter 對象上使用 getThreadsData() 方法進行訪問,如下所示:
ThreadsData hcThreadsData = HealthCenter.getThreadsData ();
ThreadsData 類包含一個 deadlockDetected() 方法,該方法在檢測到死鎖時返回 true。通過輪詢該方法,就 可以知道是否發生了死鎖:
if(hcThreadsData.deadlockDetected()) {
do something
}
訪問建議和分析引擎
Health Center 有一個內置的建議引擎,該引擎提供所有分析並返回 結果。通常,在運行完整版的 Health Center 時,通常會在 Analysis and Recommendations 面板中看到這些結果(參見 圖 9):
圖 9. Health Center 中的 Analysis and Recommendations 面板
要查詢任何建議,可采用一些方法。 getAllRecommendations() 返回所有建議的數組,但您可以只使用 getCriticalRecommendations() 調用來查詢關鍵問題, 該調用是將在 ThreadsData 對象上使用的一個調用:
String[] hcThreadsRec = hcThreadsData.getCriticalRecommendations()
查看完整的源代碼
前五個調用是在應用程序中嵌入 Health Center 以及在要監視的應用程序中檢查死鎖所必需的。清單 2 顯示了包含所用調用的完整源代碼:
清單 2. 顯示 了所使用的五個調用的完整源代碼
package deadlockdemo; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.MessageBox; import org.eclipse.swt.widgets.Shell; import com.ibm.java.diagnostics.healthcenter.api.ConnectionProperties; import com.ibm.java.diagnostics.healthcenter.api.HealthCenter; import com.ibm.java.diagnostics.healthcenter.api.factory.HealthCenterFactory; import com.ibm.java.diagnostics.healthcenter.api.threads.ThreadsData; /** * This class controls all aspects of the application's execution */ public class Application implements IApplication { HealthCenter hcMon; public Object start(IApplicationContext context) throws Exception { ConnectionProperties hcConn = new ConnectionProperties(); hcMon = HealthCenterFactory.connect(hcConn, true); try { System.out .println("Waiting for 10 seconds to allow initial data to be parsed from the connection"); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } checkForDeadlock(); return IApplication.EXIT_OK; } public void stop() { // nothing to do } public void checkForDeadlock() { while (!detectDeadlock()) { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } } } private boolean detectDeadlock() { ThreadsData hcthreadsData = hcMon.getThreadsData(); if (hcthreadsData == null) { System.out.println("No threads yet"); } else { if (hcthreadsData.deadlockDetected()) { Display display = new Display(); Shell shell = new Shell(display); MessageBox mb = new MessageBox(shell); String deadlockMessage = new String(); String[] hcThreadsRec = hcthreadsData .getCriticalRecommendations(); for (String rec : hcThreadsRec) { deadlockMessage = deadlockMessage + rec + "\n"; } mb.setMessage(deadlockMessage); mb.setText("Deadlock detected"); mb.open(); display.dispose(); return true; } } return false; } }
監視死鎖
現在,您已經在後台運行死鎖監視應用程序和有死鎖缺陷的程序。一些消息指示了存在死鎖(參見圖 10):
圖 10. 死鎖檢測結果面板
結束語
本文介紹了如何開始使用 Health Center API 的基礎知識,然後介紹了如何編寫一個用於檢查應用程序死鎖條件的監視工具。您可以應用這些技術來 提取和使用 Health Center 中的任何數據。在 第 2 部分 中,將會在這些概念上進行操作,並在死鎖檢測應用程序中添加 一個方法分析視圖,以顯示應用程序中花費最多 CPU 周期的地方。