導讀|遭受內存泄露往往是令開發者頭疼的問題,傳統分析工具 gdb、Valgrind在解決內存泄露問題上效率較低。本文特別邀請到了騰訊后臺開發工程師邢孟棒以 TDSQL實際生產中mysql-proxy內存泄露問題作為分析對象,分享其基于動態追蹤技術的通用內存泄露(增長)分析方法。其中將詳細介紹內存分配器行為分析、缺頁異常事件分析,涵蓋應用程序內存分配的常見過程。閱讀完本文后,開發者僅需關注少數可能導致內存泄露的代碼路徑,就能有效提升定位內存泄露(增長)問題的效率。
背景某個 TDSQL 私有化環境中, 中間件 mysql-proxy 進行大量請求轉發時,內存占用量持續增長導致 OOM 現象,最終影響了用戶業務的正常使用 。本人分析該問題的過程中發現一個較為普遍的業務痛點:傳統分析工具(gdb、Valgrind 等)效率相對較低,在私有化場景中尤其突出。針對這一痛點,我將提供相對通用的內存泄露(增長)分析方法,協助各位開發者更高效地定位發生泄露的代碼路徑,以期最大化減少人力投入成本并降低對用戶業務體驗的影響。
如上圖所示,現有 BCC 工具 memleak、mallocstacks 各有優劣。新工具 memstacks 結合兩者優點,允許有選擇性的生成全量內存分配火焰圖或者未釋放內存分配火焰圖需要的折疊棧格式。
對已分配但未釋放的代碼路徑展開,結果如下:
?相比全量內存分配火焰圖,數據量減少近 60 倍,需要重點關注的代碼路徑的減少也比較明顯。因此,推薦優先使用未釋放內存分配火焰圖進行分析。
相比現有版,該版本的數據量減少 20 多倍,需要重點關注的代碼路徑減少也比較明顯。
基礎概念
在展開講述內存泄露(增長)分析方法之前,我們先了解一些相關的基礎概念。 內存泄露包括內核內存泄露、應用程序內存泄露兩大類。內核內存泄露可以通過 kmemleak 進行檢測,本文主要關注應用程序的內存泄露。應用程序的內存泄露又可以細分為:堆內存(Heap)泄露、內存映射區(Memory Mappings)泄露。我們平時提及的內存泄露,主要是指物理內存的泄露(持續分配、映射實際的物理內存,且一直未釋放),危害較大,需要立即修復。 另外,虛擬內存的泄露(持續分配虛擬內存,但未分配、映射實際的物理內存)容易被忽視,雖然危害相對較小,但也需額外關注(進程的內存映射區總數量有上限,默認 1w)。 通常,應用程序內存分配涉及的步驟大致如下圖所示:第一,應用程序通過內存分配器(例如 libc)提供的 malloc 及其變體函數申請內存,free 函數釋放相應內存。第二,內存分配器(例如 libc)內部通過系統調用 brk 擴展堆內存(小塊內存分配)。第三,內存分配器(例如 libc)內部通過系統調用 mmap 分配內存映射區域(大塊內存分配,默認不小于 128 KB)第四,二或三已申請的虛擬內存在首次寫入時觸發缺頁異常,OS 分配實際物理頁面,并將虛擬內存與其相關聯,記錄至頁表。 其中,步驟一至三均為虛擬內存,步驟四分配實際物理內存并創建相應頁表。

傳統分析工具 gdb、Valgrind
在定位 mysql-proxy 內存泄露(增長)問題的過程中,開發人員嘗試使用了 Valgrind Memcheck、gdb 進行協助分析。最終前者實際效果不太理想;我通過后者分析出泄露原因,但整個過程耗費了較多時間。 gdb 是常用的程序調試工具,好處不用贅述。但對于內存泄露或增長問題,gdb 缺點也較為明顯,大致如下:干擾程序正常運行,不適合生產環境;直接定位比較困難,且要求對源碼有一定了解。 Valgrind Memcheck 是一款知名度較高的內存泄露分析工具,非常強大,開發調試過程中能夠快速發現場景的內存泄露問題。不過開發者在使用之前,建議對以下情況有所了解:第一,需要重啟程序,且作為 Valgrind 子進程運行。不適合分析正在發生內存增長的進程。第二,替代默認的 malloc/free 等分配函數,目標進程運行速度減慢 20~30 倍。第三,不能很好的支持 tcmalloc、jemalloc 內存分配器。(mysql-proxy 采用了 jemalloc 內存分配器)基于動態追蹤的通用分析方法
對于正在運行、內存持續增長的應用來說,gdb、Valgrind Memcheck 工具其實都挺難發揮價值。相比而言,動態追蹤技術提供了一種通用且易用的方式。內存分配器相關函數調用、系統調用、缺頁異常等,都可以看作一個個事件。通過對這些事件的追蹤、統計等,我們可以分析有關內存使用情況的具體代碼路徑,在不深入源碼細節的前提下快速縮小泄露發生的范圍。 本文涉及兩種基于動態追蹤的通用分析方法:內存分配器行為分析、缺頁異常事件分析,涵蓋應用程序內存分配的常見過程。1)內存分配器行為分析
內存分配器(glibc、jemalloc 等)行為分析整體思路如下:首先,站在應用視角,重點關注應用程序內存分配的代碼路徑。其次,動態追蹤內存分配相關函數,統計未釋放內存分配的調用棧與總字節數量,形成分析工具 memstacks。-
開發新工具 memstacks
如上圖所示,現有 BCC 工具 memleak、mallocstacks 各有優劣。新工具 memstacks 結合兩者優點,允許有選擇性的生成全量內存分配火焰圖或者未釋放內存分配火焰圖需要的折疊棧格式。
-
全量內存分配火焰圖
# 步驟 1. 追蹤 60s,生成全量內存分配折疊棧
# 其中,參數 -a 表示追蹤所有的 malloc 及其變體,但不追蹤 free 進行相互抵消。參數 -f 表示生成折疊棧,用于步驟 2 生成火焰圖。
./memstacks -p $(pgrep -nx mysql-proxy) -af 60 > all_mallocs.stacks
# 步驟 2. 執行下述命令生成全量內存分配火焰圖,輸出至文件 all_mallocs.svg。
./flamegraph.pl --color=mem --title="All malloc() bytes Flame Graph" --countname="bytes" < all_mallocs.stacks > all_mallocs.svg
火焰圖如下所示,可以協助開發者理解 mysql-proxy 調用 malloc 及其變體的關鍵代碼路徑。
-
未釋放內存分配火焰圖
# 步驟 1. 追蹤 60s,生成未釋放內存分配折疊棧
# 其中,參數 -f 表示生成折疊棧,用于步驟 2 生成火焰圖。
memstacks -p $(pgrep -nx mysql-proxy) -f 60 > unfreed_mallocs.stacks
# 步驟 2. 執行下述命令生成未釋放內存分配火焰圖,輸出到文件 unfreed_mallocs.svg。
./flamegraph.pl --color=mem --title="Unfreed malloc() bytes Flame Graph" --countname="bytes" < unfreed_mallocs.stacks > unfreed_mallocs.svg
火焰圖如下所示,其中:未釋放內存共計 27.75 MB(追蹤期間,通過 pidstat 觀察到 mysql-proxy 進程 RSS 增量接近 27 MB,與未釋放內存統計量 27.75 MB 基本一致)。
已分配但未釋放的代碼路徑主要有兩處。其中,據研發反饋,tdsql::set_str 正是導致 mysql-proxy 內存泄露發生的地方。而另一處并非真正的泄露。該工具有一定的副作用,由于追蹤的最后階段有一些剛分配的內存還未來得及釋放,需要進一步閱讀源碼甄別。另外,建議多運行幾次對比下結果,排除那些經常變化的分配路徑。
對已分配但未釋放的代碼路徑展開,結果如下:
?相比全量內存分配火焰圖,數據量減少近 60 倍,需要重點關注的代碼路徑的減少也比較明顯。因此,推薦優先使用未釋放內存分配火焰圖進行分析。
2)缺頁異常事件分析
相比內存分配器行為分析,缺頁異常事件分析提供了另一種視角,整體思路如下:首先,站在內核視角,關注的是首次寫入觸發缺頁異常的代碼路徑,而不是觸發內存分配的代碼路徑。前者是進程 RSS增長的原因,后者僅分配了虛擬內存,尚未映射物理內存。其次,追蹤缺頁異常事件,統計未釋放物理內存的調用棧與總頁面數量,形成分析工具 pgfaultstacks。-
現有分析工具
perfrecord-p$(pgrep-nxmysql-proxy)-epage-faults-c1-g--sleep60
BCC 工具 stackcount基于靜態追蹤點 exceptions:page_fault_user。
stackcount -p $(pgrep -nx mysql-proxy) -U tpage_fault_user
現有分析工具雖然方便,但是以增量的方式去統計,不考慮追蹤過程中被釋放的物理內存,最終統計的結果通常會偏大,對內存泄露(增長)的分析會造成干擾。
-
缺頁異常火焰圖(現有版)
perf record -p $(pgrep -nx mysql-proxy) -e page-faults -c 1 -g -- sleep 60 > pgfault.stacks
./flamegraph.pl --color=mem --title="Page Fault Flame Graph" --countname="pages" < pgfault.stacks > pgfault.svg
火焰圖具體如下,共計 420,342 次缺頁事件,但不是每一次缺頁事件都分配一個新的物理頁面(大多數情況下未分配),mysql-proxy RSS 實際增長量僅 60 多MB 。
-
開發新工具 pgfaultstacks
-
缺頁異常火焰圖
# 步驟 1. 追蹤 60s,生成缺頁異常折疊棧。其中,參數 -f 表示生成折疊棧,用于步驟 2 生成火焰圖。
pgfaultstacks -p $(pgrep -nx mysql-proxy) -f 60 > pgfault.stacks
# 步驟 2. 生成缺頁火焰圖,輸出到文件 pgfault.svg。
./flamegraph.pl --color=mem --title="Page Fault Flame Graph" --countname="pages" < pgfault.stacks > pgfault.svg
缺頁火焰圖如下,其中:共計增加 17801 個物理頁面(與 mysql-proxy 進程 RSS 增量基本一致)。重點關注函數 g_string_append_printf。(注:非內存泄露發生的環境,僅用來演示缺頁異常火焰圖)
相比現有版,該版本的數據量減少 20 多倍,需要重點關注的代碼路徑減少也比較明顯。
總結
本文以 TDSQL 實際生產中 mysql-proxy 內存泄露問題作為分析對象,探索基于動態追蹤技術的通用內存泄露(增長)分析方法:內存分配器行為分析、缺頁異常事件分析,并針對現有分析工具進行改進,形成相應的分析工具 memstacks、pgfaultstacks,歡迎各位開發者嘗試去開發。工具使用者僅需關注少數可能導致內存泄露的代碼路徑,有效提升定位內存泄露(增長)問題的效率。如果你正在遭受內存泄露(增加)的困擾,不妨嘗試下本文提及的分析方法和工具,希望有所幫助。 審核編輯 :李倩
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
內存
+關注
關注
9文章
3210瀏覽量
76377 -
代碼
+關注
關注
30文章
4968瀏覽量
73989 -
應用程序
+關注
關注
38文章
3344瀏覽量
60263
原文標題:邢孟棒:2個壓箱底的方法和工具搞定內存泄漏
文章出處:【微信號:LinuxDev,微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
熱點推薦
從架構到驅動:這三本經典書,承包了我的嵌入式Linux入門與進階
作為一個深耕嵌入式領域的開發者,書架上總有幾本“壓箱底” 的書 —— 它們既是新手入門的燈塔,也是老手復盤的手冊。今天想和大家聊聊幾本經典的書,《ARM64 體系結構編程與實踐》《鳥哥的 Linux
Linux進程管理不用愁!這6個工具幫你搞定90%場景
在 Linux 系統中,進程是資源分配的基本單位,無論是服務器運維、程序調試還是日常使用,掌握進程管理工具都是必備技能。今天就帶大家梳理 6 個最常用的進程管理工具,從查看進程到控制進程,一篇文章全
單片機的入門準備
買一塊單片機開發板,結合提供的原理圖和例程學習單片機的外設電路和片上資源的編程,每學習一個功能塊,就要把這個功能塊搞懂,切忌三天打魚兩天曬網,用學習板的弊端就是全靠自覺無人監督很容易讓板子壓箱底;
2
發表于 12-22 07:39
高壓探棒和高壓差分探頭有什么區別?
我們在使用功率放大器放大信號,或是需要檢測信號的時候,可能都會用到這樣一個測試測量設備,那就是高壓探棒和高壓差分探頭,那么你知道高壓探棒和高壓差分探頭有什么區別嗎?一、高壓探棒和差分探
ETHERCAT從站轉PROFINET,一個網關全搞定
ETHERCAT從站轉PROFINET,一個網關全搞定 在礦山深處,一套嶄新的自動化系統正悄然改變著設備保護的格局。面對井下復雜的工況和多品牌控制設備共存的現狀,我們設計的這套保護系統巧妙解決了
WebGL/Canvas 內存泄露分析
在構建高性能、長周期運行的 WebGL/Canvas 應用(如 3D 編輯器、數據可視化平臺)時,內存管理是一個至關重要且極具挑戰性的課題。 開發者通常面臨的內存泄漏問題,其根源遠比簡
效率翻倍!量產燒錄工具使用技巧大公開~
告別繁瑣燒錄流程!這款高效量產工具讓你事半功倍。今天把壓箱底的使用技巧全公開,簡單幾步輕松上手,不領真的虧了! 本文以Air780EPM開發板為例,演示量產燒錄工具的使用步驟。 ? 最新量產燒錄
at_device 包 ml307長時間運行有內存泄漏問題怎么解決?
使用 at_device 包中的 ml307 包長時間運行有大量內存泄漏問題,大概漲了20K,求助解決。
發表于 09-24 07:41
在OpenVINO? C++代碼中啟用 AddressSanitizer 時的內存泄漏怎么解決?
在 OpenVINO? C++代碼中啟用 AddressSanitizer 時遇到內存泄漏:
\"#0 0xaaaab8558370 in operator new(unsigned
發表于 06-23 07:16
鴻蒙5開發寶藏案例分享---內存優化實戰指南
,里面提供的工具和技巧簡直太香了!很多案例和方法,在實際開發中真的能救命,避免應用卡頓、崩潰,還能讓設備續航更持久。
今天就來跟大家好好分享這份寶藏,結合官方內容和我的理解,整理成這篇實戰性超強的內存優化
發表于 06-12 17:15
HarmonyOS優化應用內存占用問題性能優化一
應用開發過程中注重內存管理,積極采取措施來減少內存占用,以優化應用程序的性能和用戶體驗。
HarmonyOS提供了一些內存管理的工具和接口,幫助開發者有效地管理
發表于 05-21 11:27
快問快答:泄漏等級有哪些?含閥門氣密性檢測原理方法和解決方案
一、閥門的泄漏等級想象一下,一座化工廠的關鍵管道上,一個微小的閥門泄漏可能造成數百萬的損失甚至安全事故。這就是為什么閥門泄漏等級成為工業界的「生命線」。閥門的
推薦兩款菲力爾氣體泄漏檢測神器
在石化行業,氣體泄漏是安全生產的“大敵”。如何快速、精準地檢測泄漏,成了企業關注的焦點。今天,小菲就帶大家聊聊菲力爾的兩款“氣體泄漏檢測神器”——FLIR Si2x系列聲學成像儀和Gx
邢孟棒:2個壓箱底的方法和工具搞定內存泄漏
評論