搭配原生映像檔的 JDK Flight Recorder (JFR)

JDK Flight Recorder (JFR) 是一個事件記錄器,用於擷取有關 JVM 以及在 JVM 上執行的應用程式的資訊。GraalVM 原生映像檔支援使用 JFR 事件建置原生可執行檔,使用者可以使用 jdk.jfr.Event API,其體驗類似於在 Java HotSpot VM 中使用 JFR。

在建置時包含 JFR 支援並在執行時記錄事件 #

預設情況下,JFR 支援為停用狀態,必須在建置時明確啟用。

注意:JFR 事件記錄在 Windows 上的 GraalVM JDK 中尚不可用。

若要建置具有 JFR 的原生可執行檔,請使用 --enable-monitoring=jfr 選項

native-image --enable-monitoring=jfr JavaApplication

支援以下選項來啟動記錄,並在執行時設定記錄

  • -XX:StartFlightRecording:在應用程式啟動時啟動記錄
  • -XX:FlightRecorderLogging:設定 JFR 的記錄輸出

若要啟動 JFR 記錄,只需在執行時使用 -XX:StartFlightRecording 即可。例如

./javaapplication -XX:StartFlightRecording="filename=recording.jfr"

設定 JFR 記錄 #

與在 HotSpot 上啟動 JFR 記錄類似,您可以將以逗號分隔的鍵值對清單傳遞給 -XX:StartFlightRecording 選項來啟動記錄。例如

-XX:StartFlightRecording="filename=recording.jfr,dumponexit=true,duration=10s"

支援以下鍵值對

名稱 預設值 說明
名稱 識別記錄的名稱,例如,name=MyRecording
設定 設定檔 (profile.jfcdefault.jfc 等),例如,settings=myprofile.jfc
延遲 以 (秒)s、(分)m、(小時)h 或 (天)d 延遲記錄啟動,例如,delay=5h
期間 無限 (0) 以 (秒)s、(分)m、(小時)h 或 (天)d 為單位的記錄期間,例如,duration=300s
檔案名稱 產生的記錄檔案名稱,例如,filename=recording1.jfr
最大年齡 無限制 (0) 在磁碟上保留已記錄資料的最長時間,以 (秒)s、(分)m、(小時)h 或 (天)d 為單位,例如,60m 或 0 表示無限制。例如,maxage=1d
最大大小 無限制 (0) 在磁碟上保留的最大位元組數,以 (千)kB、(百萬)MB 或 (十億)GB 為單位,例如,500M 或 0 表示無限制。例如,maxsize=1G
dumponexit false 是否在 JVM 關閉時傾印執行中的記錄,例如,dumponexit=true

設定 JFR 系統記錄 #

您可以使用單獨的旗標 -XX:FlightRecorderLogging 來設定 JFR 系統的記錄。用法為:-XX:FlightRecorderLogging=[tag1[+tag2...][*][=level][,...]]。例如

-XX:FlightRecorderLogging=jfr,system=debug
-XX:FlightRecorderLogging=all=trace
-XX:FlightRecorderLogging=jfr*=error
  • 未設定此選項時,會以 WARNING 層級啟用記錄。
  • 當此選項設定為空字串時,會以 INFO 層級啟用記錄。
  • 當此選項設定為「disable」時,會完全停用記錄。

可用的記錄層級為:trace、debug、info、warning、error、off

可用的記錄標籤為:all、jfr、system、event、setting、bytecode、parser、metadata、dcmd

否則,此選項會預期以逗號分隔的標籤組合清單,每個組合都有可選的萬用字元 (*) 和層級。

  • 沒有層級的標籤組合會取得預設的 INFO 層級。
  • 如果符合標籤組合的層級,則會記錄具有符合特定標籤組合的標籤的訊息。
  • 如果標籤組合沒有萬用字元,則只會比對具有完全相同標籤的訊息。否則,會比對標籤是標籤組合子集的訊息。
  • 如果有多個標籤組合符合訊息的標籤,則會套用最右邊的組合。
  • 標籤沒有任何符合的標籤組合的訊息會設定為以預設的 WARNING 層級記錄。
  • 此選項不區分大小寫。

功能和限制 #

本節概述原生映像檔中可用的 JFR 功能。

方法分析和堆疊追蹤 #

JFR 中的方法分析支援兩種取樣類型:安全點取樣和非同步取樣。非同步取樣器預設為啟用,而安全點取樣器僅在需要時使用。非同步取樣的優點是避免了安全點偏差,如果分析器並未以相同的機率對應用程式中的所有點取樣,就會發生這種情況。在這種情況下,取樣器只能在安全點執行取樣,進而將偏差引入設定檔。

兩種取樣器都會以指定的頻率定期產生 jdk.ExecutionSample 事件。這些範例可以在 JDK Mission Control 或 VisualVM 等應用程式中檢視。此外,在 HotSpot 上支援堆疊追蹤的其他 JFR 事件也支援原生映像檔中的堆疊追蹤。這表示您可以執行有趣的操作,例如檢視 jdk.ObjectAllocationInNewTLAB 的火焰圖,以診斷物件配置頻繁發生的位置。

JFR 事件串流 #

原生映像檔提供 JFR 事件串流。事件串流讓您可以在應用程式層級註冊特定事件的回呼。這會對記錄的管理方式帶來更多彈性和控制。例如,如果發現事件在串流中超出特定次數,您可以動態提高事件的期間臨界值。事件串流也讓應用程式可以取得對監控目的而言很有用的持續定期 JFR 更新。

目前,串流事件上尚無提供堆疊追蹤。這表示您無法在其回呼方法內存取事件的堆疊追蹤。但是,此限制不會影響 JFR 快照檔案 (.jfr) 中的堆疊追蹤,這些仍會照常運作。

透過遠端 JMX 與 FlightRecorderMXBean 互動 #

您可以使用遠端 JMX 連線到 FlightRecorderMXBean,從程序外部與原生映像檔 JFR 互動。這可以使用 JDK Mission Control 或 VisualVM 等應用程式來完成。透過 JMX,您可以使用 FlightRecorderMXBean API 作為介面來啟動、停止和傾印 JFR 記錄。

注意:遠端 JMX 連線支援需要在建置時單獨啟用,而且是實驗性的。

FlightRecorderOptions #

您可以在執行時使用 -XX:FlightRecorderOptions 來微調 JFR 參數。這主要是針對進階使用者,大多數人應該可以使用預設參數。

洩漏分析 #

使用 jdk.OldObjectSample 事件實作的洩漏分析部分可用。具體來說,可以追蹤舊物件,但無法提供 GC 根資訊的路徑。

內建事件 #

許多 VM 層級的內建事件都可在原生映像檔中使用。在 HotSpot JVM 上透過位元組碼檢測實作的 Java 層級事件在原生映像檔中尚不可用。這類事件包括檔案 I/O 和例外狀況內建事件。

下表列出可以使用原生映像檔收集的 JFR 事件。某些事件僅在使用 Serial GC 時可用,Serial GC 是原生映像檔中的預設垃圾收集器。

事件名稱
jdk.ActiveRecording
jdk.ActiveSetting
jdk.AllocationRequiringGC 1)
jdk.ClassLoadingStatistics
jdk.ContainerCPUThrottling
jdk.ContainerCPUUsage
jdk.ContainerConfiguration
jdk.ContainerIOUsage
jdk.ContainerMemoryUsage
jdk.DataLoss
jdk.ExecutionSample
jdk.ExecuteVMOperation
jdk.GarbageCollection 1)
jdk.GCHeapSummary 1)
jdk.GCPhasePause 1)
jdk.GCPhasePauseLevel1 1)
jdk.GCPhasePauseLevel2 1)
jdk.GCPhasePauseLevel3 1)
jdk.GCPhasePauseLevel4 1)
jdk.InitialEnvironmentVariable
jdk.InitialSystemProperty
jdk.JavaMonitorEnter
jdk.JavaMonitorInflate
jdk.JavaMonitorWait
jdk.JavaThreadStatistics
jdk.JVMInformation
jdk.ObjectAllocationSample 1)
jdk.ObjectAllocationInNewTLAB 1)
jdk.OldObjectSample 2)
jdk.OSInformation
jdk.PhysicalMemory
jdk.SafepointBegin
jdk.SafepointEnd
jdk.SocketRead
jdk.SocketWrite
jdk.SystemGC 1)
jdk.ThreadAllocationStatistics
jdk.ThreadCPULoad
jdk.ThreadEnd
jdk.ThreadPark
jdk.ThreadSleep
jdk.ThreadStart
jdk.VirtualThreadEnd
jdk.VirtualThreadPinned
jdk.VirtualThreadStart

1) 如果使用 Serial GC 則可用。

2) 如果使用 Serial GC 則部分可用。

延伸閱讀 #

與我們聯繫