JVM生產環境問題定位與解決實戰(三):揭秘Java飛行記錄器(JFR)的強大功能

提到飛行記錄器,或許你的腦海中并未立刻浮現出清晰的畫面,但一說起“黑匣子”,想必大多數人都能恍然大悟,知曉其重要性及用途。在航空領域,黑匣子作為不可或缺的設備,默默記錄著飛行過程中的每一項關鍵數據,從飛行高度、速度到機艙內的對話,無一遺漏。一旦飛機發生事故,這些珍貴的數據便成為調查人員還原事件真相、精準定位事故原因的寶貴線索。

同樣地,在軟件開發的世界里,也有這樣一個“黑匣子”般的存在——Java飛行記錄器(Java Flight Recorder,簡稱JFR)。它借鑒了航空黑匣子的設計理念,卻應用于一個截然不同的領域:Java應用程序的性能分析與故障排查。

一、 背景與概述

1.1 JFR 簡介

Java Flight Recorder (JFR) 是 Oracle JDK 內置的性能分析工具,用于監控 JVM 和 Java 應用程序的運行時行為。其特點包括:

  • 低開銷:生產環境中通常僅產生 1% 左右的性能損耗
  • 實時監控:可記錄 JVM 事件、方法調用、內存分配等詳細信息、支持動態啟停記錄
  • 事件驅動:捕獲超過 200 種不同類型的事件(JDK 11+)
  • 集成分析:與 Java Mission Control (JMC) 工具深度集成
    Java飛行記錄器(Java Flight Recorder,JFR)是JVM內置的低開銷性能分析和故障排查工具,用于記錄Java應用程序運行時的詳細數據,類似飛機的“黑匣子”。它通過事件機制采集JVM和應用程序的運行時信息,包括CPU、內存、線程、垃圾回收(GC)、鎖競爭等數據,幫助開發者定位性能瓶頸和異常問題。

📌 適用場景:性能調優、內存泄漏排查、高 CPU 使用率分析等

1.2. JFR 的發展歷史

1.2.1. 關鍵里程碑
  • JRockit Flight Recorder:JFR 最初是由 BEA Systems 開發的 JRockit JVM的一部分,當時被稱為 JRockit Flight Recorder。
  • Oracle 收購 Sun Microsystems:隨著 Oracle 收購了 Sun Microsystems(Java的原始開發者)以及 BEA Systems,JFR 被集成到了 HotSpot JVM 中,并從 JDK 7u40 和 JDK 8u40開始被包含進去。此時,JFR 還是一個商業特性,需要許可證才能在生產環境中使用。
  • JDK 11:JFR 2.0版本發布,提供了更豐富的功能集。JFR 成為了 OpenJDK 的一部分,無需額外安裝。作為一個開源項目,不再需要商業許可證即可使用。
  • JDK 14:引入了 JFR Event Streaming,允許實時處理 JFR 事件。
  • JDK 17:穩定支持虛擬線程事件,并增強云原生環境兼容性。
1.2.2. Java Flight Recorder (JFR) 版本變化
JDK版本發布日期主要變化與新特性
JDK 7u402013年9月- JFR首次在Oracle JDK中作為商業特性引入
- 提供基本的事件記錄功能,如GC、線程等
- JCMD控制
JDK 8u402015年3月- 增加了更多的內置事件類型
- 改善了性能開銷,減少了對應用程序的影響
-JMX動態控制
JDK 92017年9月- 開始支持自定義事件
- 引入了更豐富的API用于編程控制JFR會話
JDK 112018年9月- JFR成為OpenJDK的一部分(JEP 328)
- JFR 2.0 版本、完全開源,社區可以貢獻代碼
- 支持JIT編譯器事件,記錄編譯器活動和性能數據
- 對容器環境的支持,更好地適應Docker等容器化部署
- 改進了數據格式和壓縮算法,提高了存儲效率
JDK 132019年9月- 引入了jdk.jfr.consumer模塊,允許程序化地讀取和分析JFR文件
- 增強了事件過濾和配置選項
JDK 142020年3月- 添加了對虛擬線程的支持(實驗性)
- 改進了事件元數據的可讀性和靈活性
JDK 152020年9月- 引入了新的事件類別,如jdk.VirtualThread*
- 改進了JFR與容器環境的兼容性
JDK 162021年3月- 支持動態調整采樣率
- 增強了對云原生環境的支持
JDK 172021年9月- 穩定版支持虛擬線程事件
- 改進了與Kubernetes等平臺的集成
- 增強了安全性,包括對敏感數據的保護
JDK 182022年3月- 引入了對GraalVM Native Image的支持
- 改進了內存管理和垃圾回收事件的詳細程度
JDK 192022年9月- 增強了對多租戶環境的支持
- 改進了事件的時間戳精度
JDK 202023年3月- 引入了新的事件類型,如jdk.CodeCacheFlush
- 改進了對異步事件的支持
JDK 212023年9月- 進一步增強了對虛擬線程的支持
- 改進了與Spring Boot等框架的集成

二、啟用 JFR

2.1. 通過命令行參數啟動

# JDK 8 需要添加以下參數,解鎖商業功能
java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder ...# JDK 11+ 開源版本直接啟用
java -XX:StartFlightRecording:delay=5s,duration=60s,name=MyRecording,filename=recording.jfr ...

常用選項:

  • filename=recording.jfr:指定輸出文件名
  • duration=60s:設置錄制時長
  • delay=10s:延遲啟動時間
  • settings=profile:使用預定義配置文件(如profile, default)
  • name=MyRecording:為錄制會話命名

2.2. 運行時觸發,使用jcmd工具

jcmd <PID> JFR.start duration=60s filename=recording.jfr
jcmd <PID> JFR.dump filename=partial.jfr
jcmd <PID> JFR.stop

2.3. 通過JMC(JDK Mission Control)啟動

操作步驟:

  1. 打開JMC工具。
  2. 連接到正在運行的JVM實例。
  3. 在左側導航欄選擇“Flight Recorder”。
  4. 配置錄制設置(如持續時間、事件類型等)。
  5. 點擊“Start Recording”。

2.4 通過Spring Boot Actuator集成啟動

2.4.1. 添加依賴

pom.xml中添加依賴:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-actuator</artifactId> 
</dependency>
2.4.2. 使用HTTP接口啟動
curl -X POST http://localhost:8080/actuator/jfr/start 
curl -X POST http://localhost:8080/actuator/jfr/dump?filename=myapp_recording.jfr 
curl -X POST http://localhost:8080/actuator/jfr/stop

三、JFR 事件

在 JFR中,一切皆為 Event!JFR 事件是 JFR 捕獲和記錄的最小數據單元,每個事件都代表了在特定時間點上系統或應用某個方面的信息。每條事件記錄包含了多個數據字段,如時間戳、事件持續時間、以及其他與業務或系統狀態相關的元數據。大部分的 Event,都有 Event 是在哪個線程發生的,Event 發生的時候這個線程的調用棧,Event 的持續時間。這就非常有用了,利用這些信息,我們可以回溯 Event 發生當時的情況。

3.1. 按來源分類

類別說明示例事件
JVM 事件JVM 內部操作產生的事件jdk.GarbageCollection, jdk.JITCompilation
JDK 庫事件JDK 類庫(如 I/O、網絡、集合)觸發的事件jdk.FileRead, jdk.SocketWrite
OS 事件操作系統級別的資源監控數據jdk.CPULoad, jdk.PhysicalMemory
自定義事件開發者定義的應用層事件com.example.OrderProcessEvent

3.2. 按觸發方式分類

  • 閾值觸發事件:當指標超過預設閾值時記錄(如 jdk.CPULoad
  • 周期采樣事件:按固定時間間隔采集(如 jdk.ThreadAllocationStatistics
  • 即時觸發事件:特定操作發生時立即記錄(如 jdk.ExceptionThrown

3.3、關鍵內置事件

3.3.1. 垃圾回收相關
事件名稱作用
jdk.GarbageCollection記錄 GC 暫停時間和原因(Young GC/Full GC)
jdk.OldObjectSample跟蹤可能引發內存泄漏的舊對象(需啟用 -XX:StartFlightRecording=old-object-queue-size=256
3.3.2. 線程與鎖
事件名稱作用
jdk.ThreadSleep記錄線程睡眠時間
jdk.JavaMonitorWait監控 synchronized 鎖等待時間
jdk.ThreadPark跟蹤 LockSupport.park() 調用(如 AQS 鎖)
3.3.3. 異常與錯誤
事件名稱作用
jdk.ExceptionThrown記錄所有異常拋出事件(包括堆棧跟蹤)
jdk.ErrorThrown記錄嚴重錯誤事件(如 OutOfMemoryError)
3.3.4. I/O 與網絡
事件名稱作用
jdk.FileRead跟蹤文件讀取操作(包含路徑和耗時)
jdk.SocketRead記錄 Socket 讀取數據量及延遲
3.3.5. JIT 與類加載
事件名稱作用
jdk.JITCompilation記錄方法編譯耗時和優化級別
jdk.ClassLoad跟蹤類加載過程及耗時

3.4. 多線程低開銷設計與異步存儲原理

3.4.1. 事件產生與多線程協作
  • 多線程事件觸發
    JFR 事件由業務線程在執行過程中主動生成(如方法調用、異常拋出、鎖競爭等),每個線程獨立維護線程本地緩沖區(Thread Local Buffer),直接以二進制格式緩存事件流。
  • 線程隔離與無鎖設計
    各線程僅操作自身緩沖區,避免全局鎖競爭,確保事件記錄低延遲(通常低于微秒級)。
3.4.2. 分級緩沖存儲流程
  1. 線程本地緩沖區(Thread Local Buffer)

    • 默認容量約 34KB,采用循環隊列結構存儲二進制事件數據。
    • 緩沖區滿時觸發異步刷寫(非阻塞),將數據批量推送至全局緩沖區。
  2. 全局緩沖區(Global Buffer)與持久化

    • 全局緩沖區整合多線程事件流,由獨立的 jfr 守護線程負責管理。
    • 后臺線程將全局緩沖區的數據異步寫入磁盤(生成 .jfr 文件),完全分離業務線程與I/O操作,避免阻塞主邏輯。
3.4.3. 高效性核心設計
  • 二進制直接存儲
    事件以二進制格式在內存中流轉,跳過多余的序列化/反序列化步驟,減少 CPU 開銷。
  • 異步分層處理
    業務線程僅負責生成事件,緩沖區刷寫與持久化由獨立線程完成,通過批量合并降低 I/O 頻率。
  • 動態采樣與可控開銷
    JFR 支持按需配置采樣率(如 -XX:FlightRecorderOptions=stackdepth=128),通過 JVM 內部 Hook 實現非侵入式監控,無需代碼插樁。
3.4.4. 自定義事件對業務的影響
  • 輕量級托管機制
    開發者通過繼承 jdk.jfr.Event 定義的事件,由 JFR 框架統一管理。調用 commit() 方法時,事件僅寫入線程本地緩沖區,不占用業務線程額外時間
  • 背壓(Backpressure)保護
    若事件產生速率超過持久化能力(如高頻自定義事件),JFR 會觸發背壓機制,選擇性丟棄低優先級事件或限制事件生成,防止資源耗盡。
  • 可控的性能損耗
    合理使用自定義事件(如避免每秒超 10 萬次高頻提交),對業務延遲的影響通常可控制在 1%~2% 以內,極端場景需結合采樣策略優化。

四、自定義事件開發

4.1. 自定義事件開發價值

通過自定義JFR事件,開發者可以:

  1. 業務指標可視化:記錄訂單創建、支付處理等關鍵業務指標
  2. 精準性能分析:追蹤特定方法執行耗時、資源消耗
  3. 上下文關聯:將JVM事件與業務邏輯關聯分析
  4. 生產環境診斷:低開銷實時監控生產系統

4.2. 自定義事件開發四部曲

4.2.1. 定義事件類
@Name("com.example.OrderCreated") 
@Label("Order Created Event")
@Category("Business")
@Description("Records order creation information")
public class OrderCreatedEvent extends Event {@Label("Order ID")public String orderId;@Label("Total Amount")@Amount(Currency.CNY)public double amount;@Label("User Type")public UserType userType;@Label("Creation Duration")@Timespan(Timespan.MILLISECONDS)public long duration;
}

注解說明:

  • @Name: 定義事件的全局唯一標識符,推薦使用反向域名命名法(類似Java包名),避免與JVM內置事件沖突。
  • @Label: 事件名稱,在JMC等可視化工具中作為顯示名稱。
  • @Category: JMC中的分類顯示,在JMC左側導航樹狀呈現。
  • @Description: 提供事件的詳細文檔說明嗎,在JMC中通過"Show Description"查看。
4.2.2. 觸發事件記錄
public class OrderService {public void createOrder(OrderRequest request) {OrderCreatedEvent event = new OrderCreatedEvent();if (event.isEnabled()) {long start = System.nanoTime();// 業務邏輯執行...event.orderId = generatedId;event.amount = calculateAmount();event.userType = getCurrentUserType();event.duration = (System.nanoTime() - start) / 1_000_000;event.commit();}}
}
4.2.2. 事件注冊與啟用
@Registered(true)
public class OrderCreatedEvent extends Event {//...
}

動態啟用配置:

jcmd <PID> JFR.configure  threshold=10ms  stacktrace=true  path-to-gc-roots=true
4.2.4. 事件數據分析

使用JMC分析:

public static void analyzeJfr(File recordingFile) throws IOException {try (RecordingStream rs = new RecordingStream(recordingFile)) {rs.onEvent("com.example.OrderCreated", event -> {System.out.printf("訂單%s 金額%.2f 耗時%dms%n",event.getString("orderId"),event.getDouble("amount"),event.getLong("duration"));});rs.start();}
}

五、高級技巧

5.1 異步事件處理

@Async
public class AsyncPaymentEvent extends Event {//...
}

5.2 閾值控制

@Threshold("20 ms")
public class SlowMethodEvent extends Event {//...
}

5.3 自定義轉換器

public class UserTypeConverter extends Converter<UserType> {public String toString(UserType type) {return type.name().toLowerCase();}
}public class OrderCreatedEvent extends Event {@Converter(UserTypeConverter.class)public UserType userType;
}

六、總結

通過自定義JFR事件,開發者可以獲得:

  • 生產環境細粒度監控能力
  • 業務與JVM事件的關聯分析
  • 傳統日志無法實現的性能洞察

建議結合JMC可視化工具和jfr命令行工具,構建完整的性能監控體系。下一篇來具體介紹使用JMC進行JFR性能分析指南。

最佳實踐:從關鍵業務路徑開始逐步增加事件埋點,通過持續的性能分析迭代優化事件配置。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/71785.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/71785.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/71785.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C#開發——ConcurrentDictionary集合

ConcurrentDictionary<TKey, TValue> 是 C# 中一個專為多線程場景設計的線程安全字典集合&#xff0c;位于 System.Collections.Concurrent 命名空間中。它允許多個線程同時對字典進行讀寫操作&#xff0c;而無需額外的同步措施。 一、集合特征 此集合有如下特征…

Unity百游修煉(2)——Brick_Breaker詳細制作全流程

一、項目簡介 Brick Breaker 是一款經典的打磚塊游戲&#xff0c;本次案例將使用 Unity 引擎來實現該游戲的核心功能。 游戲畫面如下&#xff1a; Brick_ breaker 二、項目結構概覽和前期準備 &#xff08;1&#xff09;在 Unity 項目視圖中&#xff0c;我們可以看到幾個重要…

KubeSphere平臺安裝

KubeSphere簡介 KubeSphere 是一款功能強大的容器管理平臺&#xff0c;以下是其簡介&#xff1a; 1&#xff09;基本信息 開源項目&#xff1a;基于 Apache-2.0 授權協議開源&#xff0c;由 Google Go、Groovy、HTML/CSS 和 Shell 等多種編程語言開發。基礎架構&#xff1a;…

UE5銷毀Actor,移動Actor,簡單的空氣墻的制作

1.銷毀Actor 1.Actor中存在Destory()函數和Destoryed()函數 Destory()函數是成員函數&#xff0c;它會立即標記 Actor 為銷毀狀態&#xff0c;并且會從場景中移除該 Actor。它會觸發生命周期中的銷毀過程&#xff0c;調用 Destroy() 后&#xff0c;Actor 立即進入銷毀過程。具體…

Hadoop 基礎原理

Hadoop 基礎原理 基本介紹Hadoop 的必要性Hadoop 核心組件Hadoop 生態系統中的附加組件 HDFSHDFS 集群架構HDFS 讀寫流程HDFS 寫流程HDFS 讀流程 NameNode 持久化機制 MapReduce底層原理示例 Hadoop 是一個由 Apache 基金會開發的分布式系統基礎架構&#xff0c;主要解決海量數…

Linux編輯器

1.三種模式 2.圖例 3.wq 4.光標的使用

2.24DFS和BFS刷題

洛谷P2895&#xff1a;用BFS走出危險區域&#xff0c;危險區域存在時間&#xff0c;我們用ma記錄最快變成危險區域的時間&#xff0c; 然后每次枚舉時間1然后跟ma數組比較看能不能走&#xff0c;然后時間復雜度為O(305^2)。 #include<iostream> #include<cstring>…

TMDS視頻編解碼算法

因為使用的是DDR進行傳輸&#xff0c;即雙倍頻率采樣&#xff0c;故時鐘只用是并行數據數據的5倍&#xff0c;而不是10倍。 TMDS算法流程&#xff1a; 視頻編碼TMDS算法流程實現&#xff1a; timescale 1 ps / 1ps //DVI編碼通常用于視頻傳輸&#xff0c;將并行數據轉換為適合…

C++中tuple的用法

C中tuple的用法 在C中&#xff0c;std::tuple 是一個模板類&#xff0c;用于存儲一組不同類型的值。它類似于 Python 中的元組&#xff0c;但具有更強大的功能&#xff0c;例如支持不同類型的元素和更復雜的操作。std::tuple 是 C11 標準引入的&#xff0c;位于 <tuple>…

計算機網絡————(一)HTTP講解

基礎內容分類 從TCP/IP協議棧為依托&#xff0c;由上至下、從應用層到基礎設施介紹協議。 1.應用層&#xff1a; HTTP/1.1 Websocket HTTP/2.0 2.應用層的安全基礎設施 LTS/SSL 3.傳輸層 TCP 4.網絡層及數據鏈路層 IP層和以太網 HTTP協議 網絡頁面形成基本 流程&#xff1a…

【網絡編程】廣播和組播

數據包發送方式只有一個接受方&#xff0c;稱為單播。如果同時發給局域網中的所有主機&#xff0c;稱為廣播。只有用戶數據報(使用UDP協議)套接字才能廣播&#xff1a; 廣播地址以192.168.1.0 (255.255.255.0) 網段為例&#xff0c;最大的主機地址192.168.1.255代表該網段的廣…

小程序如何實現跨頁面通信

前言 最近有很多同學問&#xff0c;小程序里面如何進行跨頁面通信。看了下之前的老代碼&#xff0c;基本都是基于onShow或者localStorage。雖然可以實現&#xff0c;但是并不怎么優雅。 今天就來聊一聊&#xff0c;小程序的跨頁面通信的幾種實現方案。或許會有你想要的方案&a…

【工具】win-畫圖 保留圖片信息并僅改變圖片比例的工具

Windows 系統自帶的“畫圖”工具 Windows 系統自帶的“畫圖”&#xff08;Paint&#xff09;工具可以進行簡單的圖片編輯&#xff0c;包括調整圖片大小和比例。 使用方法&#xff1a; 打開“畫圖”工具&#xff08;可以通過在開始菜單中搜索“畫圖”或“Paint”&#xff09;。…

如何編輯autodl中以.bashrc結尾的隱藏文件

在nnunet的運行過程中遇到了設置環境變量的問題。之前沒有接觸過linux系統&#xff0c;但是autodl里面默認是linux系統。.bashrc 是一個在 Bash shell 啟動時執行的腳本文件&#xff0c;常用于設置環境變量、定義別名、加載函數等&#xff0c;用戶可以通過編輯這個文件來定制自…

實驗3 知識表示與推理

實驗3 知識表示與推理 一、實驗目的 &#xff08;1&#xff09;掌握知識和知識表示的基本概念&#xff0c;理解其在AI中的深刻含義與意義&#xff1b; &#xff08;2&#xff09;熟悉AI中常用的知識表示方法的優缺點及其應用場景&#xff1b; &#xff08;3&#xff09;掌握產…

在 M1 Mac 上解鎖 TensorFlow GPU 加速:從環境搭建到實戰驗證

在 M1 Mac 上解鎖 TensorFlow GPU 加速&#xff1a;從環境搭建到實戰驗證 前言&#xff1a;蘋果芯片的深度學習新紀元 隨著 Apple Silicon 芯片的普及&#xff0c;M1/M2/M3 系列 Mac 已成為移動端深度學習開發的新選擇。本文將以 TensorFlow 2.x 為例&#xff0c;手把手教你如…

Python 數據分析概述 ①

一文讀懂Python數據分析&#xff1a;從基礎到實踐全攻略 在當今數字化浪潮中&#xff0c;數據分析已然成為解鎖海量數據價值的關鍵鑰匙&#xff0c;而Python憑借其獨特優勢&#xff0c;在數據分析領域大放異彩。今天&#xff0c;咱們就結合教學PPT內容&#xff0c;深入探索Pyt…

【Gin-Web】Bluebell社區項目梳理6:限流策略-漏桶與令牌桶

本文目錄 一、限流二、漏桶三、令牌桶算法四、Gin框架中實現令牌桶限流 一、限流 限流又稱為流量控制&#xff0c;也就是流控&#xff0c;通常是指限制到達系統的并發請求數。 限流雖然會影響部分用戶的使用體驗&#xff0c;但是能一定程度上保證系統的穩定性&#xff0c;不至…

Linux高并發服務器開發 第十九天(線程 進程)

目錄 1.進程組和會話 2.守護進程 2.1守護進程daemon概念 2.2創建守護進程 3.線程 3.1線程的概念 3.2線程內核三級映射 3.3線程共享 3.4線程優缺點 4.線程控制原語 4.1獲取線程id 4.2創建線程 4.3循環創建N個子線 4.4子線程傳參地址&#xff0c;錯誤示例 4.5線程…

軟件工程和系統分析與設計

軟件工程 1、軟件危機 2、軟件過程模型 2.1 瀑布模型 2.2原型模型 2.3螺旋模型 2.4敏捷模型 2.5軟件統一過程 3、軟件能力成熟度模型 CMM 4、軟件能力成熟度模型集成 CMMI 系統分析與設計 1、結構化方法SASD 1.1結構化分析 DFD 1.2結構化設計 SD-是一種面向數據流的設計…