Async-profiler 內存采樣機制解析:從原理到實現

引言

在 Java 性能調優的工具箱中,async-profiler 是一款備受青睞的低開銷采樣分析器。它不僅能分析 CPU 熱點,還能精確追蹤內存分配情況。本文將深入探討 async-profiler 實現內存采樣的多種機制,結合代碼示例解析其工作原理。

為什么需要內存采樣?

在排查 Java 應用的內存問題時,我們常常需要回答這些問題:

  • 哪些對象占用了最多的堆內存?
  • 哪些代碼路徑產生了大量臨時對象?
  • 垃圾回收頻繁的根源是什么?

async-profiler 的內存采樣功能能夠追蹤對象分配的位置和大小,幫助我們定位內存泄漏和過度分配問題。

JVM 內存分配基礎

在深入 async-profiler 的實現之前,先簡要了解 JVM 的內存分配機制:

  • TLAB(Thread Local Allocation Buffer):每個線程獨享的小型內存區域,用于快速分配小型對象
  • 大對象直接分配:超過 TLAB 大小的對象會直接在堆上分配
  • 棧上分配:某些情況下,對象可以直接在棧上分配,避免堆內存壓力

Async-profiler 內存采樣的多種機制

機制一:JVMTI ObjectSample 事件(JDK 11+)

JVMTI(Java Virtual Machine Tool Interface)提供了 ObjectSample 事件,允許在對象分配時觸發回調。這是最直接的內存采樣方式,但在 JDK 11 之前存在局限性。

// JVMTI ObjectSample 事件監聽示例
public class AllocationListener {public static void main(String[] args) throws Exception {// 通過JVMTI注冊對象分配事件Agent.setObjectAllocationCallback((thread, classDesc, size) -> {System.out.printf("分配對象: %s, 大小: %d 字節\n", classDesc, size);});// 應用代碼繼續執行// ...}
}

局限性

  • 在 JDK 11 之前,只能捕獲大對象(超過 TLAB 大小)的分配
  • 啟用該事件會帶來顯著的性能開銷

機制二:二進制插樁(JDK 11 之前的主要方式)

對于 JDK 11 之前的版本,async-profiler 采用更底層的二進制插樁技術,直接修改 HotSpot VM 的代碼。

關鍵步驟:

1. 定位目標函數:在 HotSpot VM 的二進制代碼中找到關鍵的內存分配函數

 if ((ne = libjvm->findSymbolByPrefix("_ZN11AllocTracer27send_allocation_in_new_tlab")) != NULL &&(oe = libjvm->findSymbolByPrefix("_ZN11AllocTracer28send_allocation_outside_tlab")) != NULL) {_trap_kind = 1;  // JDK 10+} else if ((ne = libjvm->findSymbolByPrefix("_ZN11AllocTracer33send_allocation_in_new_tlab_eventE11KlassHandleP8HeapWord")) != NULL &&(oe = libjvm->findSymbolByPrefix("_ZN11AllocTracer34send_allocation_outside_tlab_eventE11KlassHandleP8HeapWord")) != NULL) {_trap_kind = 1;  // JDK 8u262+} else if ((ne = libjvm->findSymbolByPrefix("_ZN11AllocTracer33send_allocation_in_new_tlab_event")) != NULL &&(oe = libjvm->findSymbolByPrefix("_ZN11AllocTracer34send_allocation_outside_tlab_event")) != NULL) {_trap_kind = 2;  // JDK 7-9} else {return Error("No AllocTracer symbols found. Are JDK debug symbols installed?");}

這個步驟需要JDK的Debug Symbols,所以很多系統比如Alpine運行的java應用就不支持內存采樣,因為Alpine的SDK為了精簡體積默認都不包含Debug Symbols。

2. 插入陷阱指令:在函數入口處寫入跳轉指令,指向自定義的處理函數

# 偽代碼:在目標函數起始位置寫入跳轉指令
push <trap_handler_address>
ret

3. 陷阱處理函數:收集分配信息并采樣堆棧

// 陷阱處理函數
void trap_handler(KlassHandle klass, HeapWord* obj) {// 獲取對象大小size_t size = get_object_size(klass);// 采樣當前線程的堆棧void* stack[100];int depth = capture_stacktrace(stack, 100);// 記錄分配事件record_allocation(obj, size, stack, depth);// 跳回原始函數繼續執行execute_original_instructions();
}

4. 恢復原始代碼:采樣結束后恢復原始指令,減少對性能的影響

這種方法雖然強大,但也有明顯缺點:

  • 與特定 JDK 版本深度耦合,兼容性差
  • 需要JDK包含Debug Symbols,很多系統比如Alpine的SDK都支持
  • 需要 root 權限才能修改運行中的 VM 進程
  • 實現復雜,稍有不慎就可能導致 JVM 崩潰

機制三:LD_PRELOAD 技術(針對堆外內存)

對于 Java 堆外內存分配(如 JNI 調用),async-profiler 使用 LD_PRELOAD 技術攔截 C 庫的內存分配函數。

// preload.c - 使用LD_PRELOAD攔截malloc
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>// 原始malloc函數指針
static void* (*real_malloc)(size_t) = NULL;// 自定義malloc函數
void* malloc(size_t size) {// 首次調用時獲取原始malloc函數地址if (!real_malloc) {real_malloc = dlsym(RTLD_NEXT, "malloc");}// 記錄分配前的時間和堆棧void* ptr = real_malloc(size);// 記錄分配信息record_allocation(ptr, size, get_current_stack());return ptr;
}

使用方式:

# 編譯共享庫
gcc -shared -fPIC preload.c -o preload.so -ldl# 運行Java程序時加載攔截庫
LD_PRELOAD=./preload.so java YourMainClass

機制四:DTrace/SystemTap(特定平臺)

在支持 DTrace 或 SystemTap 的系統中,async-profiler 可以使用這些工具進行動態插樁。

DTrace 示例:
// 監控Java對象分配的DTrace腳本
hotspot$target:::object-allocated
{// 獲取對象類型和大小@allocations[copyinstr(arg1)] = sum(arg2);// 記錄堆棧trace(arg0);ustack();
}

運行方式:

dtrace -s alloc.d -p <java_pid>

這種方法的優勢是無需修改 Java 程序或 VM,但依賴特定平臺支持。

Async-profiler 內存采樣實戰

下面通過一個簡單的 Java 程序,演示如何使用 async-profiler 進行內存采樣。

示例程序:

import java.util.ArrayList;
import java.util.List;public class MemoryAllocationDemo {public static void main(String[] args) throws InterruptedException {List<String> list = new ArrayList<>();// 生成大量字符串對象for (int i = 0; i < 1000000; i++) {list.add("Object-" + i);// 每10萬次分配休眠一下,方便我們進行采樣if (i % 100000 == 0) {Thread.sleep(100);}}System.out.println("分配完成,按任意鍵退出...");System.in.read();}
}

使用 async-profiler 進行內存采樣:

# 編譯Java程序
javac MemoryAllocationDemo.java# 運行程序
java MemoryAllocationDemo &# 獲取Java進程ID
PID=$!# 使用async-profiler進行10秒的內存分配采樣
./profiler.sh -e alloc -d 10 $PID# 生成火焰圖
./profiler.sh -e alloc -f allocation-flamegraph.svg $PID

總結

async-profiler 的內存采樣機制根據不同 JDK 版本和場景采用了多種技術:

  • JVMTI ObjectSample:簡單直接,但在 JDK 11 之前功能有限
  • 二進制插樁:強大但復雜,與特定 JDK 版本深度綁定,且需要SDK含有Debug Symbols
  • LD_PRELOAD:適用于堆外內存分配的攔截
  • DTrace/SystemTap:平臺特定但無需修改目標程序

理解這些機制有助于我們在不同場景下選擇最合適的工具和方法,更高效地解決 Java 應用的內存問題。

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

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

相關文章

Android 顏色百分比對照

本文就是簡單寫個demo,打印下顏色百分比的數值.方便以后使用. 1: 獲取透明色 具體的代碼如下: /*** 獲取透明色* param percent* param red* param green* param blue* return*/public static int getTransparentColor(int percent, int red, int green, int blue) {int alp…

MPLS-EVPN筆記詳述

目錄 EVPN簡介: EVPN路由: 基本四種EVPN路由 擴展: EVPN工作流程: 1.啟動階段: 2.流量轉發: 路由次序整理: 總結: EVPN基本術語: EVPN表項: EVPN支持的多種服務模式: 簡介: 1.Port Based: 簡介: 配置實現: 2.VLAN Based: 簡介: 配置實現: 3.VLAN Bundle: 簡…

SpringBoot自定義線程池詳細教程

文章目錄 1. 線程池基礎概念1.1 什么是線程池1.2 Java線程池核心參數1.3 線程池執行流程 2. SpringBoot中的線程池2.1 SpringBoot默認線程池2.2 SpringBoot異步任務基礎 3. 自定義線程池配置3.1 配置文件方式3.2 Java配置方式3.3 線程池工廠配置 4. 異步任務實際應用4.1 業務服…

智能快遞地址解析接口如何用PHP調用?

一、什么是智能快遞地址解析接口 隨著互聯網技術的普及和電子商務的迅猛發展&#xff0c;網購已成為現代人日常生活的重要組成部分。然而&#xff0c;在這個便捷的背后&#xff0c;一個看似不起眼卻影響深遠的問題正悄然浮現——用戶填寫的快遞地址格式混亂、信息不全甚至錯漏…

概率分布,支撐AI算法的數學基石

概率分布,是現代人工智能(AI)算法不可或缺的數學語言。它不僅描述了數據中的不確定性,更揭示了機器學習模型背后的本質運作機制。本文將帶你深入了解概率分布的數學本質,以及它在監督學習、深度學習、生成模型等核心AI領域的關鍵作用,揭秘概率論如何成為AI理論和實踐的強…

2025年Splunk的替代方案:更智能的安全選擇

在安全信息和事件管理&#xff08;SIEM&#xff09;領域&#xff0c;2025年的競爭愈發激烈。Splunk憑借其強大的功能和穩定性長期占據市場主導地位&#xff0c;但其高昂的成本、復雜性和擴展性挑戰促使許多企業轉向其他解決方案。無論是初創公司、快速發展的中型企業&#xff0…

(10)Fiddler抓包-Fiddler如何設置捕獲Firefox瀏覽器的Https會話

1.簡介 經過上一篇對Fiddler的配置后&#xff0c;絕大多數的Https的會話&#xff0c;我們可以成功捕獲抓取到&#xff0c;但是有些版本的Firefox瀏覽器仍然是捕獲不到其的Https會話&#xff0c;需要我們更進一步的配置才能捕獲到會話進行抓包。 2.環境 1.環境是Windows 10版…

simulink mask的使用技巧

1.mask界面布局 1.1如何調整控件的位置和控件大小&#xff1f; 反正2020a是調不了&#xff0c; 找了好久&#xff0c;只能是調布局&#xff0c;例如你要調成下面這樣&#xff1a; 第一個控件的iTem location屬性選擇New row 后面跟著的幾個和第一個同一行的空間屬性選擇Cu…

Go中MAP底層原理分析

MAP底層原理分析 參考 https://golang.design/go-questions/map/principalmap | Golang 中文學習文檔 先來看一下map結構體&#xff0c;&#xff08;runtime.hmap結構體就是代表著 go 中的map&#xff0c;與切片一樣map的內部實現也是結構體&#xff09; type hmap struct {/…

#開發環境篇:postMan可以正常調通,但是瀏覽器里面一直報403

本地header代理下面內容即可 headers: { // 添加必要的請求頭 ‘Host’: ‘服務端域名’, ‘Origin’: https://服務端域名, ‘Referer’: https://服務端域名 }, devServer: {// 本地開發代理API地址proxy: {^/file: {target: https://服務端域名,changeOrigin: true, // 是否…

【論文閱讀 | PR 2024 |ICAFusion:迭代交叉注意力引導的多光譜目標檢測特征融合】

論文閱讀 | PR 2024 |ICAFusion&#xff1a;迭代交叉注意力引導的多光譜目標檢測特征融合 1.摘要&&引言2.方法2.1 架構2.2 雙模態特征融合&#xff08;DMFF&#xff09;2.2.1 跨模態特征增強&#xff08;CFE&#xff09;2.2.2 空間特征壓縮&#xff08;SFS&#xff09;…

效率、便捷、安全:智慧充電樁一站式解決方案如何重塑新能源充電體驗?

在新能源浪潮席卷全球的背景下&#xff0c;電動汽車的普及對充電基礎設施提出了更高要求。傳統充電模式因效率低、操作繁瑣、安全隱患等問題&#xff0c;難以滿足用戶需求。智慧充電樁一站式解決方案應運而生&#xff0c;通過技術創新將效率、便捷與安全融為一體&#xff0c;徹…

杰發科技AC7840——Timer修改重裝載值

需要在運行過程中修改定時器的中斷時間 int main(void) {SystemClock_Config(); /*時鐘初始化*/GPIO_LedInit(); /*GPIO初始化*/TIMER_Init(); /*定時器初始化*/InitDebug(); …

https和http有什么區別-http各個版本有什么區別

http和 https的區別 HTTP&#xff08;超文本傳輸協議&#xff09;和 HTTPS&#xff08;安全超文本傳輸協議&#xff09;是兩種用于在網絡上傳輸數據的協議&#xff0c;它們的主要區別在于安全性&#xff1a; HTTP&#xff08;Hypertext Transfer Protocol&#xff09;&#x…

低秩矩陣、奇異值矩陣和正交矩陣

低秩矩陣 低秩矩陣&#xff08;Low-rank Matrix&#xff09;是指秩&#xff08;rank&#xff09;遠小于其行數和列數的矩陣&#xff0c;即 r a n k ( M ) r ? min ? ( m , n ) rank(M) r \ll \min(m,n) rank(M)r?min(m,n)。其核心特點是信息冗余性&#xff0c;可通過少量…

對抗性提示:大型語言模型的安全性測試

隨著大語言模型&#xff08;LLM&#xff09;在虛擬助手、企業平臺等現實場景中的深度應用&#xff0c;其智能化與響應速度不斷提升。然而能力增長的同時&#xff0c;風險也在加劇。對抗性提示已成為AI安全領域的核心挑戰&#xff0c;它揭示了即使最先進的模型也可能被操縱生成有…

SSM 框架核心知識詳解(Spring + SpringMVC + MyBatis)

&#x1f331; 第一部分&#xff1a;Spring 核心原理與使用 1. 什么是 Spring Spring 是一個開源的 Java 企業級開發框架&#xff0c;旨在簡化 Java 企業應用程序開發。它核心思想是控制反轉&#xff08;IoC&#xff09;和面向切面編程&#xff08;AOP&#xff09;&#xff0…

基于 Alpine 定制單功能用途(kiosk)電腦

前言 故事回到 7 年前, 在網上沖浪的時候發現了一篇介紹使用 Ubuntu 打造 kiosk 單功能用途電腦的文章, 挺好玩的, 就翻譯了一下并比葫蘆畫瓢先后用了 CentOS 7, ArchLinux 進行了實現. 歷史文章: 翻譯 - 使用Ubutnu14.04和Chrome打造單功能用途電腦(大屏展示電腦) 使用CentOS…

【機器學習及深度學習】機器學習模型的誤差:偏差、方差及噪聲

機器學習模型的誤差分析 V1.0機器學習模型的衡量準則概念引入機器學習模型誤差分析誤差出現的原因及消除 V1.0 機器學習模型的衡量準則 衡量機器學習模型的好壞可以考慮以下幾個方面&#xff1a; 偏差&#xff08;Bias&#xff09;&#xff1a; 在充分訓練的情況下&#xff0…

混沌映射(Chaotic Map)

一.定義 混沌映射是指一類具有混沌行為的離散時間非線性動力系統&#xff0c;通常由遞推公式定義。其數學形式為 &#xff0c;其中 f 是非線性函數&#xff0c;θ 為參數。它們以簡單的數學規則生成復雜的、看似隨機的軌跡&#xff0c;是非線性動力學和混沌理論的重要研究對象…