Health Center 是一款適用於 Java 的 IBM監視和診斷工具,是一個免費的低開銷診斷工具和 API,用於監視在 IBM Java 虛擬機 (JVM) 上運行的應用程序。有關此 API 可以執行的操作的細節,請參閱 第 1 部分。在本文中,將會采用 第 1 部分中開發的死鎖檢測應用程序,並添加一個方法分析視圖來顯示應用程序的哪些地方花費了大部分的 CPU 周期。(請 參閱 下載,以便獲得示例的完整源代碼。)
系統要求
Health Center API bundle 至少需要安裝 Eclipse 3.4 或 Eclipse 4.x。
測試應用程序
在 第 1 部分中,已經測試了生成死鎖條件的應用程序。在本文中,我 們將使用該應用程序的修訂版,該版本包含一些會給 CPU 施加壓力的功能。請參閱 下載,以獲得相關的源代碼。清單 1 顯示了一個代碼片段示例:
清單 1. 新的 GenerateDeadLock 源代碼的代碼片段
private class runSlowMethods extends Thread { public void run() { SlowClassAndMethod1 sCAM1 = new SlowClassAndMethod1(); SlowClassAndMethod2 sCAM2 = new SlowClassAndMethod2(); sCAM1.start(); sCAM2.start(); } private class SlowClassAndMethod1 extends Thread { public void run() { while (true) { slowMethod1(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } private void slowMethod1() { String largeString = new String("a string to add"); for (int i = 0; i < 1000000; i++) { largeString.concat(largeString); } } } private class SlowClassAndMethod2 extends Thread { public void run() { while (true) { slowMethod2(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } private void slowMethod2() { HashMap map = new HashMap(); String largeString = new String("another string to add"); for (int i = 0; i < 1000000; i++) { map.put(i, largeString); largeString.concat(largeString); } }
通過與該程序連接的 Health Center 代理啟動該程序。要使用 Java 5 SR10 及更高版本、Java 6 SR5 及 更高版本和 Java 7 並通過代理來啟動該應用程序,請使用以下命令(參見圖 1):
java -Xhealthcenter GenerateDeadlock
圖 1. 啟動應用程序
要使用 Java 5 SR9 及其早期版本或者 Java 6 SR4 及其早期版本並通過代理來啟動應用程序,請使用:
java -agentlib:healthcenter - Xtrace:output=healthcenter.out GenerateDeadlock
您可以下載 IBM 開發人員工具包。
編寫增強的監視應用程序
要修改您在 第 1 部分中創建的 DeadlockDemo 應用程序,請打開 Application.java 文件(參見圖 2):
圖 2. 打開 Application.java
將 Application.java 中的所有代碼 替換為源代碼(參見 下載)。清單 2 顯示了一個代碼片段示例:
清單 2. Application.java 替換代碼的代碼片段
private class ProfileApplication extends Thread { String methodTree = null; public void run() { try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } while (keepRunning) { analyzeMethods(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } } private void analyzeMethods() { ProfilingData profilingData; profilingData = hcMon.getProfilingData(); if (profilingData == null) { return; } MethodProfileData[] mPD = profilingData.getProfilingEvents(); if (mPD != null) { final SimpleProfileData[] sPD = new SimpleProfileData[mPD.length]; int index = 0; for (MethodProfileData mP : mPD) { methodTree = new String(); sPD[index] = new SimpleProfileData(); sPD[index].setCount(mP.getMethodSampleCount()); sPD[index].setMethodName(mP.getMethodName()); MethodProfilingNode[] mPN = mP.getCallingMethods(); for (MethodProfilingNode node : mPN) { if (node instanceof MethodProfilingNode) { walkProfileTree(node); } } sPD[index].setMethodTree(methodTree); index++; } Arrays.sort(sPD); display.asyncExec(new Runnable() { public void run() { profileText.setText("method: " + sPD[0].getMethodName() + "\n sample count: " + sPD[0].getCount() + "\n" + sPD[0].getMethodName() + sPD[0].getMethodTree()); shell.redraw(); } }); } }
該代碼不同於原始代碼,但大部分更改都是為了設置應用程序的顯示和應用正確的應用程序行為。實際的 Health Center API 代碼僅包含對方法分析數據的更多調用,您會在下一節中看到這些調用。
對數據進行分析
Health Center 使用了一個基於樣例的分析器,該分析器為您提供了一個應用程序所使用的所 有方法的樣例視圖。該分析器對於確定性能瓶頸非常有用,因為您的應用程序可能在某個方法中花費了太多的時間,從而導 致性能問題。
要訪問分析數據,請使用一個與訪問線程數據的調用類似的調用:
ProfilingData profilingData = HealthCenter.getProfilingData();
ProfilingData類包含幾個方法,這些方法提供了對所有抽樣 方法、樣例計數和調用層次結構的訪問。
方法 getProfilingEvents()返回 MethodProfileData的一個數組,其中包 含每個抽樣方法的條目。對於每個抽樣方法,可以使用 getMethodSampleCount()獲取樣例計數,使用 getMethodName()獲 取方法名稱,並使用 getCallingMethods() 調用它的方法。
使用這些方法可生成大多數樣例方法的調用層次結構。 然後可以使用該信息來提高所監視應用程序的性能。
監視死鎖和方法分析
現在,您已經擁有了新的死鎖和分析監視應用程序,並且改進了受感染死鎖的程序正在後台運行。運行此死鎖和分析 監視應用程序可以查看應用程序監視窗口上的 “已檢測到的死鎖” 消息(參見圖 3):
圖 3. 監視死鎖
顯然,您 已經擁有了一些數據。現在讓我們來理解一下它們的含義。
分析數據的含義
在頂部面板中,樣例計數會隨著 應用程序的運行而增加,顯示該方法占用了大多數 CPU 周期。清單 3 僅顯示了頂部方法的輸出:
清單 3. 輸出頂 部方法
profileText.setText("method: " + sPD[0].getMethodName() + "\n sample count: " + sPD[0].getCount() + "\n" + sPD[0].getMethodName() + sPD[0].getMethodTree());
但是,您可以通過循環 sPD 數組中的所有元素來輸出更多的方法。
當在 Health Center 中運行分析器時,如 果某個方法正在堆棧上運行 Java 代碼,那麼該方法將會獲得計數。方法擁有的樣例越多,它所執行的工作也就越多。樣例 計數可能無法反映調用方法的頻率。但它可以表明相對於應用程序中的其他方法該方法指定的工作的多少。
在這個 示例中,您可以看到方法 java.util.HashMap.rehash(int)是抽樣最多的方法。它的調用堆棧(調用它的起始位置)顯示它 源自 GenerateDeadlock$runSlowMethods$SlowClassAndMethod2.run()中的某個調用。
查看層次結構中的下一個調 用,run()方法調用了 GenerateDeadlock$runSlowMethods$SlowClassAndMethod2.slowMethod2(),但它還負責調用 java.util.HashMap.put。這會最終導致調用 rehash()。
如果查看死鎖應用程序中的 slowMethod2()方法,就會看 到一個循環,該循環將條目置於 HashMap 中(參見清單 4):
清單 4. 將條目置於 HashMap 中的循環
private void slowMethod2() { HashMap map = new HashMap(); String largeString = new String("another string to add"); for (int i = 0; i < 1000000; i++) { map.put(i, largeString); largeString.concat(largeString); } }
您可以在該方法中注釋掉該循環,如清單 5 所示:
清單 5. 注釋掉循環
private void slowMethod2() { HashMap map = new HashMap(); String largeString = new String("another string to add"); // for (int i = 0; i < 1000000; i++) { // map.put(i, largeString); // largeString.concat(largeString); // } }
如果再次運行測試應用程序,然後運行新的死鎖和分析工具,您會注意到該問題已得到解決。一個新的方法出 現在分析面板中(參見圖 4):
圖 4. 問題已解決 — 出現了新的方法
現在可以再次啟動該過程(確定熱門 方法並幫助解決性能瓶頸)。
結束語
這些文章介紹了如何開始使用 Health Center API 的基礎知識。您可 以應用這些技術來提取和使用 Health Center 中的任何數據。例如,僅當 WebSphere方法變為熱門方法或者似乎因為應用 程序內存不足而觸發系統轉儲時,可以使用此 API 獲取這些方法的詳細信息。
下載