程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> J2EE >> 你不知道的Java秘密(2)

你不知道的Java秘密(2)

編輯:J2EE

5個命令行分析工具

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

JDK包括很多命令行實用程序,可以用於監控和管理Java應用程序性能。雖然大多數這類應用程序都被標注為“實驗型”,在技術上不受支持,但是它們很有用。

1.jps(sun.tools.jps)

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

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

在Java進程中使用jps

與配置JDK的大部分工具及本文中提及的所有工具一樣,可執行jps通常是一個圍繞Java類或執行大多數工作的類集的一個薄包裝。在Windows®環境下,這些工具是.exe文件,使用JNIInvocationAPI直接調用上面提及的類;在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選項

  1. -class
  2. -compiler
  3. -gc
  4. -gccapacity
  5. -gccause
  6. -gcnew
  7. -gcnewcapacity
  8. -gcold
  9. -gcoldcapacity
  10. -gcpermcapacity
  11. -gcutil
  12. -printcompilation

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

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

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

  1. 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查詢看起來如下:

  1. select s from Java.lang.String s where s.count >= 100

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

  1. select referrers(f) from Java.io.File f

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

結束語

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved