JVM 如何使用性能分析工具定位代碼中的性能問題?

核心思想: 通過工具觀察程序在特定負載下的運行狀態,識別消耗資源最多的代碼段(熱點代碼)、異常的內存分配模式或線程阻塞情況,然后針對性的優化代碼。

通用步驟:

  1. 確定問題: 首先明確遇到了什么性能問題,例如:CPU 使用率過高、內存持續增長最終 OOM、響應時間突然變慢、吞吐量下降等。
  2. 選擇工具: 根據問題的類型和你的環境選擇合適的性能分析工具。
  3. 連接或啟動分析: 將工具連接到目標 JVM 進程,或者啟動帶有特定分析功能的 JVM。
  4. 施加負載: 模擬實際的用戶負載,讓問題得以重現。
  5. 收集數據: 在負載持續期間,使用工具收集性能數據(CPU 采樣、內存快照、線程轉儲等)。
  6. 分析數據: 使用工具提供的分析功能,解讀收集到的數據。
  7. 定位代碼: 根據分析結果,確定具體是哪個類、哪個方法、哪行代碼導致了性能問題。
  8. 優化代碼: 針對定位到的問題代碼進行優化。
  9. 驗證效果: 重新運行負載測試,驗證優化是否解決了問題并達到了性能目標。

常用工具及其定位代碼問題的方法:

  1. jstack (線程堆棧分析)

    • 作用: 獲取 JVM 中所有線程的堆棧信息。主要用于分析線程阻塞、死鎖、以及線程在做什么(例如是否在等待 I/O、等待鎖)。
    • 定位代碼問題:
      • 高 CPU 但堆棧顯示大量 WAITING/TIMED_WAITING: 可能線程在等待某個條件或鎖,但等待時間過長。查看這些線程的堆棧,能看到它們在哪個方法、哪個鎖上等待。
      • 大量 BLOCKED 狀態線程: 表明存在嚴重的鎖競爭。查看這些 BLOCKED 線程的堆棧,以及它們試圖獲取的鎖(“waiting for monitor…”),再看擁有這個鎖的線程(“owned by…”)在做什么。這能幫助我們定位競爭鎖的同步代碼塊。
      • 死鎖: jstack 會在最后輸出明確報告,可以幫助我們發現死鎖,并列出涉及的線程和鎖。
      • 線程長時間停留在某個方法: 如果看到很多線程的堆棧頂部停留在某個特定方法,并且狀態不是 BLOCKED/WAITING,可能這個方法本身執行緩慢。
    • 使用方法: jstack <pid> (pid 是 Java 進程 ID)。可以多次采集(例如每隔幾秒采集一次),以便觀察線程狀態的變化。
  2. jmap (內存分析 - 堆轉儲)

    • 作用: 生成 JVM 堆內存的快照(Heap Dump),或者打印堆內存的統計信息。主要用于分析內存使用情況、查找內存泄漏。
    • 定位代碼問題:
      • 內存泄漏: 生成堆轉儲文件 (jmap -dump:format=b,file=heap.bin <pid>) 后,使用 Eclipse MAT (Memory Analyzer Tool) 或 VisualVM 的 HeapWalker 打開分析。這些工具可以計算對象的“保留大小”(即該對象被垃圾回收后能釋放的總內存),列出按保留大小排序的對象,找出最大的對象集合。通過分析對象的引用鏈(Paths To GC Roots),可以找到為什么這些對象沒有被回收,通常能定位到是哪個類、哪個靜態變量、哪個集合等持有了不必要的引用。
      • 對象創建率過高/大對象: 分析堆轉儲也能看到各種對象的實例數量和總大小。如果某個類的對象數量異常龐大,或者有些對象占用了大量內存,我們需要檢查創建這些對象的代碼。雖然 jmap 本身不提供創建時機的追蹤,但結合代碼邏輯分析堆內容,可以回溯到創建點。
    • 使用方法: jmap -dump:format=b,file=/path/to/heap.hprof <pid>。分析 .hprof 文件通常需要專業的 GUI 工具。
  3. jstat (JVM 統計監控)

    • 作用: 監控 JVM 的各種運行時統計信息,如 GC 情況、堆內存使用、類加載等。
    • 定位代碼問題:
      • GC 頻繁或停頓長: jstat -gc <pid> <interval> <count> 可以實時輸出 Young GC (YGC) 和 Full GC (FGC) 的次數和耗時。如果 YGC 次數非常多,或者 FGC 頻繁且耗時很長,說明內存分配和回收是瓶頸。這本身不直接指向代碼,但它指示我們需要關注代碼中的對象創建行為和內存使用模式。頻繁的 YGC 可能意味著新生代太小或對象創建速度太快;頻繁 FGC 可能意味著老年代滿得快,需要檢查是否有大量對象晉升或存在內存泄漏。
    • 使用方法: jstat -gc <pid> 2s 10 (每 2 秒輸出一次,共 10 次)。
  4. VisualVM (集成工具)

    • 作用: 一個免費的、集成的可視化工具,可以監控 CPU、內存、線程,并進行 CPU 和內存分析(Profiling)。支持插件擴展。
    • 定位代碼問題:
      • CPU 性能分析 (Profiler -> CPU): 這是 VisualVM 定位 CPU 熱點代碼的主要功能。它可以通過采樣(Sampling)或插樁(Instrumentation)兩種方式記錄方法調用的耗時。運行 CPU Profiler 一段時間后,它會列出消耗 CPU 時間最多的方法列表(按百分比排序)。點擊具體方法,可以查看它的調用者(Callers)和被調用者(Callees),以及完整的調用樹(Call Tree)。通過分析調用樹,可以精確地找到是哪個方法(及其調用路徑)占用了大量的 CPU 時間。
      • 內存性能分析 (Profiler -> Memory): 可以記錄一段時間內的對象創建情況,顯示哪些類創建的對象最多,以及它們占用的內存。結合 Heap Dump 功能(Monitor -> Heap Dump),進行內存泄漏分析(與 MAT 功能類似,查找大對象和引用鏈)。
      • 線程分析 (Threads): 提供實時的線程狀態視圖,可以方便地看到 BLOCKED, WAITING, RUNNABLE 狀態的線程數量,并可以一鍵生成線程轉儲進行分析(類似于 jstack,但可視化)。
    • 使用方法: 啟動 VisualVM,連接到本地或遠程的 Java 進程。
  5. JMC (Java Mission Control) / JFR (Java Flight Recorder)

    • 作用: Oracle 官方推薦的強大工具集。JFR 以極低的開銷收集 JVM 和應用程序的事件數據(包括 GC、線程活動、I/O、鎖、JIT 編譯、方法執行等)。JMC 用于打開并分析 JFR 記錄文件。
    • 定位代碼問題:
      • CPU 熱點: JFR 記錄的方法采樣事件能精確地展示哪些方法在 CPU 上運行時間最長,JMC 提供火焰圖(Flame Graph)或樹狀圖等多種視圖來分析 CPU 采樣數據,非常直觀地找到熱點方法及其調用鏈。
      • 鎖競爭: JFR 會記錄線程等待鎖的事件,JMC 的 Lock Analysis 視圖能清晰地顯示哪些鎖競爭最激烈,哪些線程等待時間最長,以及發生在哪個類的哪個方法中。
      • I/O 瓶頸: JFR 記錄文件 I/O、Socket I/O 等事件,可以定位代碼中低效的 I/O 操作。
      • GC 瓶頸: JFR 詳細記錄 GC 事件,JMC 提供豐富的 GC 分析視圖,結合 CPU 使用率分析,能確定 GC 是否是導致高 CPU 的原因,以及哪些代碼行為(如大量對象創建)導致了 GC 壓力。
      • 異常與錯誤: JFR 記錄異常拋出事件,能幫你找到代碼中頻繁發生異常的位置(即使異常被捕獲)。
    • 使用方法:
      • 啟動 JFR recording: 使用 jcmd <pid> JFR.start ... 或在 JVM 啟動參數中設置 -XX:+UnlockCommercialFeatures -XX:+FlightRecorder (對于舊版本 Oracle JDK) 或 -XX:StartFlightRecording=... (對于 OpenJDK)。
      • 生成 JFR 文件: 使用 jcmd <pid> JFR.dump ... 或在 recording 結束時自動生成。
      • 分析: 啟動 JMC,打開生成的 .jfr 文件進行分析。
  6. Async-Profiler

    • 作用: 一個采樣式的低開銷性能分析工具,支持分析 CPU、堆分配、鎖競爭、I/O 等。可以直接 attach 到正在運行的 JVM。
    • 定位代碼問題: 提供火焰圖、樹狀圖等多種輸出格式,能快速準確地定位 CPU 熱點、高內存分配點、鎖競爭發生的代碼位置,對 C/C++ 代碼和 JVM 內部活動也有很好的支持。
    • 使用方法: 作為一個 native 庫加載或通過 async-profiler.sh 腳本運行。例如 async-profiler.sh start <pid> -e cpu -f profile.html

定位代碼問題時的技巧:

  • 結合多種工具: 通常不會只使用一個工具。例如,先用 jstat 或 VisualVM 監控 GC 和 CPU 趨勢,發現問題后,用 jstack 分析線程狀態,用 VisualVM 或 JMC/JFR 進行 CPU/Memory Profiling,如果懷疑內存泄漏則使用 jmap/MAT 分析堆轉儲。
  • 關注熱點: 性能分析工具通常會列出消耗資源最多的前 N 個方法或類。優先分析這些“熱點”。
  • 分析調用樹/引用鏈: 不要只看單個方法消耗的時間或單個類占用的內存,更重要的是理解它是如何被調用的(調用樹)或為什么沒有被回收(引用鏈)。這能幫助你找到問題的源頭。
  • 多點采樣: 對于線程分析 (jstack) 或某些 Profiling 工具,采集單次數據可能不夠,需要間隔一定時間多次采集,觀察狀態的變化。
  • 理解工具的工作原理: 知道工具是采樣式還是插樁式,以及其開銷,有助于更準確地使用和解讀結果。
  • 聯系代碼邏輯: 分析結果最終需要回到代碼層面。結合應用的業務邏輯和代碼實現,我們要理解為什么這段代碼會成為瓶頸。
  • 環境一致性: 盡量在與生產環境相似的環境中進行性能分析。

熟練使用這些工具,并結合對 JVM 運行時原理和自身代碼邏輯的理解,就能有效地定位并解決 Java 應用程序的性能問題。

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

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

相關文章

Python虛假新聞檢測識別

程序示例精選 Python虛假新聞檢測識別 如需安裝運行環境或遠程調試&#xff0c;見文章底部個人QQ名片&#xff0c;由專業技術人員遠程協助&#xff01; 前言 這篇博客針對《Python虛假新聞檢測識別》編寫代碼&#xff0c;代碼整潔&#xff0c;規則&#xff0c;易讀。 學習與應…

網絡原理 - 12(HTTP/HTTPS - 3 - 響應)

目錄 認識“狀態碼”&#xff08;status code&#xff09; 200 OK 404 Not Found 403 Forbidden 405 Method Not Allowed 500 Internal Server Error 504 Gateway Timeout 302 Move temporarily 301 Moved Permanently 418 I am a teaport 狀態碼小結&#xff1a; …

Spring Boot中集成Guava Cache或者Caffeine

一、在Spring Boot(1.x版本)中集成Guava Cache 注意&#xff1a; Spring Boot 2.x用戶&#xff1a;優先使用Caffeine&#xff0c;性能更優且維護活躍。 1. 添加依賴 在pom.xml中添加Guava依賴&#xff1a; <dependency><groupId>com.google.guava</groupId&…

Linux工作臺文件操作命令全流程解析

全文目錄 1 確認當前工作路徑2 導航與目錄管理2.1 關鍵命令2.2 邏輯銜接 3 文件基礎操作3.1 創建 → 備份 → 重命名 → 清理3.2 文件查看和編輯3.3 文件鏈接3.4 文件diff 4 文件權限與所有權管理5 文件打包與歸檔6 參考文獻 寫在前面 shell是一種命令解釋器&#xff0c;它提供…

LeetCode第183題_從不訂購的客戶

LeetCode 第183題&#xff1a;從不訂購的客戶 題目描述 表: Customers ---------------------- | Column Name | Type | ---------------------- | id | int | | name | varchar | ---------------------- id 是該表的主鍵。 該表包含消費者的 id 和…

c語言的常用關鍵字

c語言的常用關鍵字 c語言的關鍵字表示數據類型的關鍵字autocharfloatdoubleintlongshortvoidsignedstruct、enum、unionunsigned 表示分支語句的關鍵字ifelseswitchbreakcasecontinuedefault 表示循環語句的關鍵字whiledoforgoto 用于修飾變量或函數的關鍵字constconst修飾變量…

MCU通用輸入輸出端口(GPIO)設計指南

在嵌入式系統開發中&#xff0c;MCU的GPIO接口是一個基礎但非常實用的功能模塊。GPIO全稱是通用輸入輸出端口&#xff0c;它讓MCU可以靈活地與外部設備進行交互。 GPIO的主要特點包括&#xff1a; 多功能性&#xff1a;每個引腳都可以單獨配置為輸入或輸出 可編程性&#xff…

STM32完整內存地址空間分配詳解

在STM32這類基于ARM Cortex-M的32位微控制器中&#xff0c;整個4GB的地址空間(從0x00000000到0xFFFFFFFF)有著非常系統化的分配方案&#xff0c;每個區域都有其特定的用途。下面我將詳細介紹這些地址區域的分配及其功能&#xff1a; STM32完整內存地址空間分配詳解(0x00000000…

實現水平垂直居中的多種方法

在前端開發中&#xff0c;元素的居中是一個常見但又經常讓人頭疼的問題。本文將全面總結各種CSS居中方法&#xff0c;特別是如何實現一個div的水平垂直居中。 為什么居中這么重要&#xff1f; 居中布局是現代網頁設計中最基礎也最重要的布局方式之一。無論是導航菜單、登錄框…

如何實現服務的自動擴縮容(Auto Scaling)

在云計算和分布式系統的時代,系統的彈性和適應性已成為企業構建高效IT基礎設施的核心需求。自動擴縮容(Auto Scaling)作為一種關鍵技術,旨在根據實時負載變化動態調整計算資源,以確保系統性能穩定,同時優化資源利用效率。簡單來說,自動擴縮容是指系統能夠根據預設規則或…

uniapp+vue3+ts 使用canvas實現安卓端、ios端及微信小程序端二維碼生成及下載

加粗樣式uniapp多端生成帶二維碼海報并保存至相冊的實現 在微信小程序開發中&#xff0c;我們常常會遇到生成帶有二維碼的海報并保存到手機相冊的需求&#xff0c;比如分享活動海報、產品宣傳海報等。今天就來和大家分享一下如何通過代碼實現這一功能。 準備工作 在開始之前&am…

架構師面試(三十八):注冊中心架構模式

題目 在微服務系統中&#xff0c;當服務達到一定數量時&#xff0c;通常需要引入【注冊中心】組件&#xff0c;以方便服務發現。 大家有沒有思考過&#xff0c;注冊中心存在的最根本的原因是什么呢&#xff1f;注冊中心在企業中的最佳實踐是怎樣的&#xff1f;注冊中心的服務…

Day.js和Moment.js對比,日期時間庫怎么選?

在JavaScript的日期處理庫中&#xff0c;Moment.js 和 Day.js 是兩個非常流行的選擇。本文將基于從npmtrends的數據&#xff0c;對這兩個庫進行詳細的對比分析。 Moment.js的重度使用者。凡是遇到時間和日期的操作&#xff0c;就把Moment.js引用上。 直到有天我發現加載的mome…

羅默如何用木星衛星“宇宙鐘表”測量光速?

一、17世紀的“宇宙級實驗” 1676年&#xff0c;丹麥天文學家奧勒羅默&#xff08;Ole Rmer&#xff09;在巴黎天文臺做出驚人發現&#xff1a; 木星衛星的“遲到早退”現象&#xff0c;竟能揭示光速的秘密&#xff01; 通過觀察木衛一&#xff08;Io&#xff09;的軌道周期變…

deepseek 技巧整理

1、導出word 和excel 功能&#xff0c;在使用以下提示詞。 請幫我列出減肥期間可以吃的水果&#xff0c;并分析該水果含有的營養元素&#xff0c;以表格的形式星現。1.要以html的方式輸出 2.要可以直接運行 3.頁面要提供可以直接下載word和excel功能

思考軟件框架

數據庫是達夢數據庫 假定里面有40張表&#xff0c;軟件的業務邏輯比較復雜。 當然&#xff0c;依然是對數據庫中數據的增&#xff0c;刪&#xff0c;改&#xff0c;查&#xff0c;組合&#xff0c;顯示。 但是也涉及到多種軟件&#xff0c;多臺設備之間的通信。 我們可以使用…

探索 Disruptor:高性能并發框架的奧秘

在當今的軟件開發領域&#xff0c;處理高并發場景是一項極具挑戰性的任務。傳統的并發解決方案&#xff0c;如基于鎖的隊列&#xff0c;往往在高負載下表現出性能瓶頸。而 Disruptor 作為一個高性能的并發框架&#xff0c;憑借其獨特的設計和先進的技術&#xff0c;在處理海量數…

前端面經-VUE3篇--vue3基礎知識(一)插值表達式、ref、reactive

一、計算屬性(computed) 計算屬性&#xff08;Computed Properties&#xff09;是 Vue 中一種特殊的響應式數據&#xff0c;它能基于已有的響應式數據動態計算出新的數據。 計算屬性有以下特性&#xff1a; 自動緩存&#xff1a;只有當它依賴的響應式數據發生變化時&#xff…

數據結構6 · BinaryTree二叉樹模板

代碼函數功能順序如下&#xff1a; 1&#xff1a;destroy&#xff1a;遞歸刪除樹 2&#xff1a;copy&#xff1a;復制二叉樹 3&#xff1a;preOrder&#xff1a;遞歸前序遍歷 4&#xff1a;inOrder&#xff1a;遞歸中序遍歷 5&#xff1a;postOrder&#xff1a;遞歸后續遍…

C++/SDL進階游戲開發 —— 雙人塔防游戲(代號:村莊保衛戰 13)

&#x1f381;個人主頁&#xff1a;工藤新一 &#x1f50d;系列專欄&#xff1a;C面向對象&#xff08;類和對象篇&#xff09; &#x1f31f;心中的天空之城&#xff0c;終會照亮我前方的路 &#x1f389;歡迎大家點贊&#x1f44d;評論&#x1f4dd;收藏?文章 文章目錄 十…