關於 Java 性能監控您不知道的 5 件事

 

關於 Java 性能監控您不知道的 5 件事,第 2 部分

利用 JDK 內置分析器進行 Java 進程監控

Ted Neward, 主管, Neward & Associates

 

簡介: 如果 JDK 中配置有全功能分析器 JConsole 對於您還是條新聞的話,本文中將介紹的 5 個獨立分析實用程序可能會使您感到更加驚奇。您將瞭解輕量級(有時是實驗型) Java™ 進程監控和分析工具如何幫助您應對線程飢餓、死鎖及對象泄露等性能瓶頸問題。

 

 

 

 

發佈日期: 2010 年 9 月 03 日 
級別: 初級  其他語言版本: 英文 
建議: 0 (添加評論)

1 star2 stars3 stars4 stars5 stars 平均分 (共 0 個評分 )

 

關於該系列

您覺得自己懂 Java 編程?事實上,大多數程序員對於 Java 平臺都是淺嘗輒止,只學習了足以完成手頭上任務的知識而已。在 本系列 中,Ted Neward Ted Neward 深入挖掘 Java 平臺的核心功能,揭示一些鮮爲人知的事實,幫助您解決最棘手的編程困難。

全功能內置分析器,如 JConsole 和 VisualVM 的成本有時比它們的性能費用還要高 — 尤其是在生產軟件上運行的系統中。因此,在聚焦 Java 性能監控的第 2 篇文章中,我將介紹 5 個命令行分析工具,使開發人員僅關注運行的 Java 進程的一個方面。

JDK 包括很多命令行實用程序,可以用於監控和管理 Java 應用程序性能。雖然大多數這類應用程序都被標註爲 “實驗型”,在技術上不受支持,但是它們很有用。有些甚至是特定用途工具的種子材料,可以使用 JVMTI 或 JDI(參見 參考資料)建立。

1. jps (sun.tools.jps)

很多命令行工具都要求您識別您希望監控的 Java 進程。這與監控本地操作系統進程、同樣需要一個程序識別器的同類工具沒有太大區別。

“VMID” 識別器與本地操作系統進程識別器(“pid”)並不總是相同的,這就是我們需要 JDK jps 實用程序的原因。

在 Java 進程中使用 jps

與配置 JDK 的大部分工具及本文中提及的所有工具一樣,可執行 jps 通常是一個圍繞 Java 類或執行大多數工作的類集的一個薄包裝。在 Windows® 環境下,這些工具是 .exe 文件,使用 JNI Invocation API 直接調用上面提及的類;在 UNIX® 環境下,大多數工具是一個 shell 腳本的符號鏈接,該腳本採用指定的正確類名稱開始一個普通啓動程序。

如果您希望在 Java 進程中使用 jps(或者任何其他工具)的功能 — Ant 腳本 — 僅在每個工具的 “主” 類上調用main() 相對容易。爲了簡化引用,類名稱出現在每個工具名稱之後的括號內。

jps — 名稱反映了在大多數 UNIX 系統上發現的 ps 實用程序 — 告訴我們運行 Java 應用程序的 JVMID。顧名思義,jps 返回指定機器上運行的所有已發現的 Java 進程的 VMID。如果 jps 沒有發現進程,並不意味着無法附加或研究 Java 進程,而只是意味着它並未宣傳自己的可用性。

如果發現 Java 進程,jps 將列出啓用它的命令行。這種區分 Java 進程的方法非常重要,因爲只要涉及操作系統,所有的 Java 進程都被統稱爲 “java”。在大多數情況下,VMID 是值得注意的重要數字。

使用分析器開始

使用分析實用程序開始的最簡單方法是使用一個如在demo/jfc/SwingSet2 中發現的 SwingSet2 演示一樣的演示程序。這樣就可以避免程序作爲背景/監控程序運行時出現掛起的可能性。當您瞭解工具及其費用後,就可以在實際程序中進行試用。

加載演示應用程序後,運行 jps 並注意返回的 vmid。爲了獲得更好的效果,採用 -Dcom.sun.management.jmxremote 屬性集啓動 Java 進程。如果沒有使用該設置,部分下列工具收集的部分數據可能不可用。

 

2. jstat (sun.tools.jstat)

jstat 實用程序可以用於收集各種各樣不同的統計數據。jstat 統計數據被分類到 “選項” 中,這些選項在命令行中被指定作爲第一參數。對於 JDK 1.6 來說,您可以通過採用命令 -options 運行 jstat 查看可用的選項清單。清單 1 中顯示了部分選項:


清單 1. jstat 選項

				
-class
-compiler
-gc
-gccapacity
-gccause
-gcnew
-gcnewcapacity
-gcold
-gcoldcapacity
-gcpermcapacity
-gcutil
-printcompilation 

實用程序的 JDK 記錄(參見 參考資料)將告訴您清單 1 中每個選項返回的內容,但是其中大多數用於收集垃圾的收集器或者其部件的性能信息。-class 選項顯示了加載及未加載的類(使其成爲檢測應用程序服務器或代碼中 ClassLoader 泄露的重要實用程序,且 -compiler 和 -printcompilation 都顯示了有關 Hotspot JIT 編譯程序的信息。

默認情況下,jstat 在您覈對信息時顯示信息。如果您希望每隔一定時間拍攝快照,請在 -options 指令後以毫秒爲單位指定間隔時間。jstat 將持續顯示監控進程信息的快照。如果您希望 jstat 在終止前進行特定數量的快照,在間隔時間/時間值後指定該數字。

如果 5756 是幾分鐘前開始的運行 SwingSet2 程序的 VMID,那麼下列命令將告訴 jstat 每 250 毫秒爲 10 個佚代執行一次 gc 快照轉儲,然後停止:


jstat -gc 5756 250 10

請注意 Sun(現在的 Oracle)保留了在不進行任何預先通知的情況下更改各種選項的輸出甚至是選項本身的權利。這是使用不受支持實用程序的缺點。請參看 Javadocs 瞭解 jstat 輸出中每一列的全部細節。

 

3. jstack (sun.tools.jstack)

瞭解 Java 進程及其對應的執行線程內部發生的情況是一種常見的診斷挑戰。例如,當一個應用程序突然停止進程時,很明顯出現了資源耗盡,但是僅通過查看代碼無法明確知道何處出現資源耗盡,且爲什麼會發生。

jstack 是一個可以返回在應用程序上運行的各種各樣線程的一個完整轉儲的實用程序,您可以使用它查明問題。

採用期望進程的 VMID 運行 jstack 會產生一個堆轉儲。就這一點而言,jstack 與在控制檯窗口內按 Ctrl-Break 鍵起同樣的作用,在控制檯窗口中,Java 進程正在運行或調用 VM 內每個 Thread 對象上的 Thread.getAllStackTraces() 或Thread.dumpStack()jstack 調用也轉儲關於在 VM 內運行的非 Java 線程的信息,這些線程作爲 Thread 對象並不總是可用的。

jstack 的 -l 參數提供了一個較長的轉儲,包括關於每個 Java 線程持有鎖的更多詳細信息,因此發現(和 squash)死鎖或可伸縮性 bug 是極其重要的。

 

4. jmap (sun.tools.jmap)

有時,您正在處理的問題是一個對象泄露,如一個 ArrayList (可能持有成千上萬個對象)該釋放時沒有釋放。另一個更普遍的問題是,看似從不會壓縮的擴展堆,卻有活躍的垃圾收集。

當您努力尋找一個對象泄露時,在指定時刻對堆及時進行拍照,然後審查其中內容非常有用。jmap 通過對堆拍攝快照來提供該功能的第一部分。然後您可以採用下一部分中描述的 jhat 實用程序分析堆數據。

與這裏描述的其他所有實用程序一樣,使用 jmap 非常簡單。將 jmap 指向您希望拍快照的 Java 進程的 VMID,然後給予它部分參數,用來描述產生的結果文件。您要傳遞給 jmap 的選項包括轉儲文件的名稱以及是否使用一個文本文件或二進制文件。二進制文件是最有用的選項,但是隻有當與某一種索引工具 結合使用時 — 通過十六進制值的文本手動操作數百兆字節不是最好的方法。

隨意看一下 Java 堆的更多信息,jmap 同樣支持 -histo 選項。-histo 產生一個對象文本柱狀圖,現在在堆中大量引用,由特定類型消耗的字節總數分類。它同樣給出了特定類型的總示例數量,支持部分原始計算,並猜測每個實例的相對成本。

不幸的是,jmap 沒有像 jstat 一樣的 period-and-max-count 選項,但是將 jmap(或 jmap.main())調用放入 shell 腳本或其他類的循環,週期性地拍攝快照相對簡單。(事實上,這是加入 jmap 的一個好的擴展,不管是作爲 OpenJDK 本身的源補丁,還是作爲其他實用程序的擴展。)

 

5. jhat (com.sun.tools.hat.Main)

將堆轉儲至一個二進制文件後,您就可以使用 jhat 分析二進制堆轉儲文件。jhat 創建一個 HTTP/HTML 服務器,該服務器可以在瀏覽器中被瀏覽,提供一個關於堆的 object-by-object 視圖,及時凍結。根據對象引用草率處理堆可能會非常可笑,您可以通過對總體混亂進行某種自動分析而獲得更好的服務。幸運的是,jhat 支持 OQL 語法進行這樣的分析。

例如,對所有含有超過 100 個字符的 String 運行 OQL 查詢看起來如下:


select s from java.lang.String s where s.count >= 100

結果作爲對象鏈接顯示,然後展示該對象的完整內容,字段引用作爲可以解除引用的其他鏈接的其他對象。OQL 查詢同樣可以調用對象的方法,將正則表達式作爲查詢的一部分,並使用內置查詢工具。一種查詢工具,referrers() 函數,顯示了引用指定類型對象的所有引用。下面是尋找所有參考 File 對象的查詢:


select referrers(f) from java.io.File f 

您可以查找 OQL 的完整語法及其在 jhat 瀏覽器環境內 “OQL Help” 頁面上的特性。將 jhat 與 OQL 相結合是對行爲不當的堆進行對象調查的有效方法。

 

結束語

當您需要近距離觀察 Java 進程內發生的事情時,JDK 的分析擴展會非常有用。本文中介紹的所有工具都可以從命令行中由其自己使用。它們還可以與 JConsole 或 VisualVM 有力地結合使用。JConsole 和 VisualVM 提供 Java 虛擬機的總體視圖,jstat 和 jmap 等有針對性的工具支持您對研究進行微調。

走進 5 件事 系列: 編寫腳本。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章