Java Mission Control-Java 性能分析工具

引言

本文爲 Java 性能分析工具系列文章第三篇,這裏將介紹如何使用 Java 任務控制器 Java Mission Control 深入分析 Java 應用程序的性能,爲程序開發人員在使用 Java 任務控制器的時候提供幫助。第一篇:操作系統工具第二篇:Java 內置監控工具

JMC 是在 JAVA 7u40 發佈中加入的性能監控工具。使用過 JDK 6 中 JRockit JVM 的用戶並不會陌生,因爲它是 Java 7 中 JMC 功能的一部分。啓動 JMC 後將會顯示當前機器中的所運行的 JVM 進程信息,當然我們也可以選擇添加更多的 JVM 進程進行監控。圖 1 中展示了使用 JMC 監控 GlassFish 應用服務器的畫面。圖中展示了被監控程序的基本信息,其包括 CPU 使用率和內存堆的使用率,值得注意的是,JMC 監控圖中顯示的是當前機器的 CPU 的使用情況,可以看到的是 JMC 監控的是整個系統,而並非只是被選中的 JVM 對 CPU 的使用情況。通過自定義設置上方儀表盤中顯示的信息,既可以查看 被監控 JVM 的詳細信息,例如垃圾回收,類的加載,線程的使用,以及內存堆的使用率,等等。也可以查看指定操作系統信息,例如系統的 CPU 和內存的使用率,磁盤的交換信息,平均負載等相關信息。

圖 1. Java Mission Control 監控圖

圖 1. Java Mission Control 監控圖

 

回頁首

JFR (Java Flight Recorder)

JFR 是 JMC 中一個非常關鍵的功能。它記錄了 JVM 所有事件的歷史數據,通過這些數據,程序性能分析人員可以結合以往的歷史數據對 JVM 性能瓶頸進行分析診斷。

JFR 的基本操作是開啓一系列的事件(例如,一個線程爲了等待鎖而被阻塞)。當某個事件發生時,這個事件的所有數據將會被保存至內存或者一個文件當中。數據流被保留在一個環形緩存中,所以只有最近發生的事件的數據纔是可用的。JMC 可以從 JVM 或者文件中讀取並展示這些事件數據,通過這些數據,可以進行性能分析。

通過 JVM 參數,JMC 用戶界面以 jcmd 命令,可以指定上文中提到的事件類型、環形緩存的大小、數據存儲的位置等信息。在默認設置下,JMC 對被監控應用的影響非常小。但是隨着越來越多的事件被開啓,以及觸發事件的閥值的改變,JMC 的影響也在變化。接下來將展示 JFR 的用戶界面。

JFR 概述

這個例子使用 JFR 記錄 GlassFish 應用服務器的 6 分鐘內的相關數據。圖 2 展示了 JMC 將這些數據加載之後的到總體視圖。

圖 2. JMC 數據加載示例圖

圖 2. JMC 數據加載示例圖

這張圖上的信息類似於 JMC 基本信息監控所看到的畫面。上面的儀表盤顯示的是 CPU 使用率和內存堆使用率,在其上方有一條標示事件順序的時間軸,垂直柱狀體代表事件。可以放大時間軸中感興趣的部分進行詳細分析,就像圖中所示,從 6 分鐘的時間軸選出位於末端的 1 分 6 秒進行放大。

圖 2 中 CPU 使用率曲線非常清楚的看到,GlassFish 服務器所在 JVM 平均大約 70%的使用率,而機器整體的 CPU 使用率達到 100%。在最下端,有一些標籤可以選擇,系統屬性標籤,JVM 信息標籤等,在畫面左側的按鈕提供更加詳細的應用程序運行狀況。

JFR 內存視圖

JFR 內存視圖收集的信息非常豐富,下圖只展示了其中的一部分。從圖 3 中可以看出,新生代(Young Generation) 佔用的內存大小在週期性地進行有規律的波動。但有趣的是,由於沒有對象需要移入老年代,應用整體的內存堆大小並沒有增長。左下角面板中展示在監控期間所有類型的垃圾回收事件,在本例中一直爲 ParallelScavenge。當選中一個事件時,右下角將更加細化的顯示此事件,包括此事件的所有階段以及每個階段的時間消耗。

圖 3. 新生代內存使用情況示例圖

圖 3. 新生代內存使用情況示例圖

從圖中各種各樣的標籤可以看到包含了豐富的信息,其中包括引用對象被清理的時間和數量,併發回收器中是否有 Promotion 失敗或者 Evacuation 失敗,垃圾回收器自身算法的配置,等等信息。

JFR 代碼視圖

JFR 代碼視圖展示了從記錄的數據中獲得的基礎分析信息。如圖 4 所示,第一個標籤頁顯示了所有的包名,在其他分析工具我們並沒見過類似的功能。可以看出圖中使用 Java.Math 方法的執行佔應用程序所有方法調用運行總時長的比重爲 41%。傳統的分析視角位於底部,例如熱點方法和被分析代碼的調用如下圖所示。

圖 4. Java Flight Recorder 代碼視圖

圖 4. Java Flight Recorder 代碼視圖

與其它分析軟件不同,JFR 提供更多模式的代碼可視化。Throwables 標籤頁展示應用中的異常處理,還有展示編譯器工作信息的標籤頁。

JMC 還提供線程視圖,I/O 視圖,系統視圖,所有的這些視圖都是爲了更好的分析 JFR 所記錄的真實事件。

JFR 事件概述

JFR 記錄並保存事件流,JMC 提供不同的視圖來分析這些事件,但是 JFR 事件面板(如圖 5 所示)纔是分析事件最有效的途徑。

圖 5. Java Flight Recorder 事件視圖

圖 5. Java Flight Recorder 事件視圖

通過左側面板的過濾器可以過濾顯示的事件,在圖中,只選擇了應用級的事件。需要注意的是,只有在 JFR 記錄保存事件中指定的事件類型纔會出現在這裏,在這裏只能在此基礎上進行過濾。

從圖 5 中可以看出,在 66 秒內,應用程序產生 6 種類型的事件,其中 10612 個 JVM 事件和 1536 個 JDK 庫事件。線程 Park 和 Monitor 事件消耗時間長的原因在前文中已有討論,在此不再贅述。應用程序有多個線程共消耗 40 秒向套接字內寫數據(Socket Write),這對於一個使用 4 核的應用來說是一個正常值,但仍然可以通過減少向套接字內寫入的數據量來提高性能。

同樣的,應用程序中多個線程共消耗 143 秒從套接字讀取數據 (Socket Read)。這看起來並不正常,通過查看這些事件的處理記錄可以發現,由多個線程使用阻塞式 I/O 讀取並不連續的管理請求。這些管理請求的時間間隔通常很長,但這些線程卻在 read() 方法內被阻塞,所以導致這些線程讀取數據時消耗了過多的時間。

對於 Monitor 事件,

準性能分析器可以提供線程被阻塞之後調用 CPU 和操作系統代碼等待解鎖的相關信息,而 Java 本地分析器能夠提供這些 CPU 和操作系統代碼執行的記錄,正如 JVM 直接將這些信息提供給 JFR。

JFR 事件是直接獲得於 JVM 之內,通過這些事件能夠非常詳細的瞭解應用程序內部的運行狀況,這是其他工具所不能比的。事件的類型非常之多,在不同版本的 JDK 之間也有所差異。下面列出一些常用的事件類型,第一行描述可以由其他工具獲得的信息,第二行描述除了使用 JFR 無法獲得信息。

  • Classloading

    被加載的類的數量和未被加載的類的數量

    加載類的類加載器(classloader),加載一個類需要的時間

  • Thread statistics

    創建線程的數量、銷燬線程的數量、線程快照(dump)

    阻塞指定線程的鎖以及被指定鎖阻塞的線程

  • Throwables

    應用程序實用的異常類

    應用程序拋出的異常和錯誤的數量以及創建異常和錯誤的棧記錄

  • TLAB allocation

    內存堆中已分配的數量、TLAB(Thread-Local Allocation Buffers)的大小

    在內存對中指定對象的內存分配以及爲這些對象分配內存的棧記錄

  • File and socket I/O

    進行 I/O 消耗的時間

    每一次讀寫調用的時間消耗,讀寫操作消耗時間過長的文件或套接字

  • Monitor blocked

    等待監控器的線程

    阻塞某個線程的監控器、線程被阻塞的時間

  • Code cache

    代碼緩存的大小以及內容

    從代碼緩存中移除的方法、代碼緩存的配置

  • Code compilation

    哪些方法被編譯,OSR 編譯,編譯耗時

    JFR 中沒有額外的信息,但 JFR 總結了多個源文件的信息

  • Garbage collection

    GC 的次數,包括每一個階段的次數、每個代的大小

    JFR 中沒有額外的信息,但 JFR 總結了來自多個工具的信息

  • Profiling

    檢測分析和採樣分析

    JFR 並不能獲得分析器獲得的豐富信息,但 JFR 提供了更高層次的概述

 

回頁首

開啓 JFR

Java Flight Recorder - JFR 默認被設置爲關閉狀態。通過在啓動應用程序的命令中加入-XX:+UnlockCommercialFeatures –XX:+FlightRecorder 參數來開啓 JFR,以及相關的一些功能。但是值得注意的是這個命令只是開啓了 JFR 功能,但並沒有開啓記錄進程各種事件,這就需要我們在開啓了 JFR 功能之後,必須通過用戶界面或者命令行來開啓記錄運行線程產生記錄的功能。

通過 JMC 開啓 JFR

最簡單的方式是通過 JMC 來開啓 JFR,當 JMC 啓動後,界面上將顯示當前系統中所有的 JVM 進程。JVM 進程以樹形結構展示,展開 JVM 進程節點,通過 Flight Recorder 按鈕開啓 Flight Recorder 窗口,如圖 6 所示。

圖 6. Java Flight Recorder 記錄窗口視圖

圖 6. Java Flight Recorder 記錄窗口視圖

Flight Recorder 有兩種模式,固定時長模式(圖中爲 1 分鐘)和持續模式,在持續模式中,使用環形緩存保存最近的事件。

在進行前瞻性分析(Proactive Analysis)時,例如在進行負載測試時開始記錄事件,應該使用固定時長模式,這樣可以很好的瞭解 JVM 在負責測試期間的表現。

持續模式適合反應(Reactive)分析,這樣可以使 JVM 保存最近的事件並導出記錄響應這些事件的數據。舉例來說,Weblogic 應用服務中可以設置觸發器,在應用服務器響應了一個反常事件之後導出相關數據。

通過命令行開啓 JFR

在 JVM 啓動參數中加入-XX:+FlightRecorderOption=參數啓動記錄事件。參數爲一個以逗號間隔的鍵值對數據。下面將介紹這些選項:

  • name=name

    指定記錄的名稱

  • defaultrecording=true/false

    是否在初始化時啓動記錄事件,默認爲 false,對於反應分析,應設置爲 true

  • settings=path

    JFR 配置文件的路徑

  • delay=time

    開始記錄前的延時

  • duration=time

    記錄持續時間

  • filename=path

    保存記錄事件的文件路徑

  • compress=true/false

    是否使用 gzip 壓縮記錄數據,默認爲 false

  • maxage=time

    環形緩存中保存記錄的數據的最長時間

  • maxsize=size

    環形緩存佔用的最大空間

爲了更靈活的使用 JFR,在運行過程中可以使用 jcmd 命令來動態改變這些選項的值。下面將介紹使用 jcmd 來設置 JFR 相關選項的命令。

% jcmd process_id JFR.start [option_list]

option_list 是以逗號分隔的鍵值對,選項與上述選項一致。當使用持續模式記錄事件時,可以使用下面的命令將環形緩存中的數據導出至文件中:

% jcm process_id JFR.dump [option_list]

選項包括:

  • name=name

    指定導出數據的事件記錄名

  • recording=n

    JFR 事件記錄號

  • filename=path

    導出文件的路徑

一個進程下可能有多個 JFR 事件記錄在運行,可以通過下面的命令查看當前所有的事件記錄:

% jcmd process_id JFR.check [verbose]

這些不同的事件記錄以名字或者隨機的記錄號進行區分。使用下面的命令可以停止一個進程內正在運行的事件記錄:

% jcmd process_id JFR.stop [option_list]

選項包括:

  • name=name

    需要停止的事件記錄名

  • recording=n

    需要停止的事件記錄號

  • discard=Boolean

    如果爲 true,捨棄之前保存的數據

  • filename=path

    保存數據的文件路徑

 

回頁首

選擇 JFR 事件

JFR 目前支持 77 種事件類型,大多數類型的事件爲週期性事件,每隔固定時間將會產生一次,其他類型的事件爲觸發型,只有當達到某種設定的閥值後被觸發,也就是說纔會被 JFR 發現並監控起來。

收集事件數據自然會影響應用程序性能,影響的大小由開啓記錄的事件的類型和數量有關。默認情況下,並沒有開啓所有事件類型的記錄,將對性能影響較大的 6 種類型事件關閉,以此達到將 JFR 對應用程的影響降到 1%以內。

但有時開啓一些對應用影響較大的事件類型是值得的,例如 TLAB 是默認關閉的事件類型,但是它能夠幫助人們發現某些對象是否在分配內存時直接進入老年代(Old Generation)。同樣的,Profiling 事件雖然默認開啓,但是每 20 毫秒觸發一次,這樣很容以導致採樣分析出現錯誤。

JFR 記錄的事件定義在一個模版中,可以通過 settings 選項指定。JFR 運行時有兩個模版:

  1. 默認模版:事件對應用性能的影響在 1%以內
  2. 分析模版:設置大部分基於閥值(Threshhold)的事件爲 10 毫秒觸發一次,分析模版對應用性能的影響大約爲 2%。

這些模版由 JMC 模版管理器(Template Manager)管理,模版管理器通過 JMC 中相應的按鈕啓動。存儲模版的目錄有兩個:$HOME/.JMC/<release>directory 和$JAVA_HOME/jre/lib/jfr。在模版管理器中,可以選擇一個全局模版、本地模版或者定義一個新模版。定義一個新模版是時,需要指定可用的事件,指定這些事件默認的狀態爲開啓或者關閉,同時可以定義這些事件的閥值。

在圖 7 中,File Read 事件被開啓並且設置閥值爲 15 毫秒,即當讀取文件超過 15 毫秒時,此事件將觸發。同時此事件還被設置爲 File Read 事件生成棧記錄,由於這將增加事件對應用性能的影響,所以將此選項設置爲可選配置項。

圖 7. Java Flight Recorder 事件模板示例圖

圖 7. Java Flight Recorder 事件模板示例圖

事件模版文件爲 xml 文件,所以通過讀取 xml 文件很容易可以判斷某個事件是否開啓。也可以將本地模版文件拷貝至全局模版目錄供其他用戶和團隊使用。

Java Flight Recorder(JFR)提供了深入 JVM 內部去看運行時的狀態。這是由於 JFR 其本身就是 Java 的一部分內嵌其中的。如同其他工具,JFR 的使用某種程度上增加了對應用程序性能的開銷。常規的使用 JFR 還是可以幫助我們收集大量的信息,而且對性能的開銷是較低的。

 

回頁首

總結

到此爲止,本系列文章已經將常用的 Java 性能分析工具進行了介紹,我們都知道一個優秀的性能分析工具是我們在分析性能問題的關鍵,但是不能完全,甚至過分的依賴工具所能展現的表面,我們更應當銘記,沒有最好的工具,只有是否適合的工具,正如我們講過的工具 A 也許適合大多數的應用程序分析,但是它卻不能夠揭示工具 B 所能指出的問題,所以我們應當學會靈活自由的使用這些工具。

對於性能分析人員來說命令行工具也是非常有幫助,所以不要拒絕它所能帶來的強大力量。它往往能在自動化的性能監控,或者性能測試中發揮巨大作用。

希望這些介紹能夠給性能調優人員和開發人員的日常工作帶來幫助。俗話說金無足赤,人無完人,工具亦如此。每一個工具都有其各自的優劣勢,只有充分了解每個工具適合的場景,才能讓這些工具揚長避短,更加充分地發揮其作用。

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