吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

glibc導致的堆外內存泄露的排查過程

OSC開源社區 ? 來源:阿里云開發者 ? 2023-09-01 09:43 ? 次閱讀

阿里妹導讀

本文記錄一次glibc導致的堆外內存泄露的排查過程。

問題現象

團隊核心應用每次發布完之后,內存會逐步占用,不重啟或者重新部署就會導致整體內存占用率超過90%。

dcb20a6c-47ef-11ee-97a6-92fbcf53809c.png

發布2天后的內存占用趨勢

探索原因一

堆內找到原因

出現這種問題,第一想到的就是集群中隨意找一臺機器,信手dump一下內存,看看是否有堆內存使用率過高的情況。 dcd53b36-47ef-11ee-97a6-92fbcf53809c.png 內存泄露 dd002152-47ef-11ee-97a6-92fbcf53809c.png 泄露對象占比 發現 占比18.8%

問題解決

是common-division這個包引入的

dd21defa-47ef-11ee-97a6-92fbcf53809c.png 暫時性修復方案

當前加載俄羅斯(RU)國際地址庫,改為一個小國家地址庫 以色列(IL)

當前業務使用場景在補發場景下會使用,添加打點日志,確保是否還有業務在使用該服務,沒人在用的話,直接下掉(后發現,確還有業務在用呢 )。

完美解決問題,要的就是速度!!發布 ~~上線!!順道記錄下同一臺機器的前后對比。 dd482650-47ef-11ee-97a6-92fbcf53809c.png

發布后短時間內有個內存增長實屬正常,后續在做觀察。

發布第二天,順手又dump一下同一臺機器的內存 ddd00f98-47ef-11ee-97a6-92fbcf53809c.png 由原來的18.8%4.07%的占比,降低了14%,牛皮!! 傻了眼,內存又飆升到86%~~ 該死的迷之自信!! ddf63baa-47ef-11ee-97a6-92fbcf53809c.png 發布后內存使用率

探索原因二

沒辦法匯報了~~~ 但是問題還是要去看看為什么會占用這么大的內存空間的~

查看進程內存使用

de43352c-47ef-11ee-97a6-92fbcf53809c.png

java 進程內存使用率 84.9%,RES 6.8G。

查看堆內使用情況

當期機器配置為 4Core 8G,堆最大5G,堆使用為不足3G左右。

deb48d9e-47ef-11ee-97a6-92fbcf53809c.png 使用arthas的dashboard/memory 命令查看當前內存使用情況: def96b12-47ef-11ee-97a6-92fbcf53809c.png 當前堆內+非堆內存加起來,遠不足當前RES的使用量。那么是什么地方在占用內存??

開始初步懷疑是『堆外內存泄露』

開啟NMT查看內存使用

筆者是預發環境,正式環境開啟需謹慎,本功能有5%-10%的性能損失!!!

-XX:NativeMemoryTracking=detail


jcmd pid VM.native_memory
df3a66a8-47ef-11ee-97a6-92fbcf53809c.png 如圖有很多內存是Unknown(因為是預發開啟,相對占比仍是很高)。

概念 NMT displays “committed” memory, not "resident" (which you get through the ps command). In other words, a memory page can be committed without considering as aresident(until it directly accessed).

rssAnalyzer 內存分析

筆者沒有使用,因為本功能與NMT作用類似,暫時沒有截圖了~ rssAnalyzer(內部工具),可以通過oss在預發/線上下載。

通過NMT查看內存使用,基本確認是堆外內存泄露。 剩下的分析過程就是確認是否堆外泄露,哪里在泄露。

堆外內存分析

查了一堆文檔基本思路就是

pmap 查看內存地址/大小分配情況

確認當前JVM使用的內存管理庫是哪種

分析是什么地方在用堆外內存。

內存地址/大小分配情況

pmap 查看

pmap -x 2531 | sort -k 3 -n -r
df8c4630-47ef-11ee-97a6-92fbcf53809c.png

劇透: 32位系統中的話,多為1M 64位系統中,多為64M。

strace 追蹤

由于系統對內存的申請/釋放是很頻繁的過程,使用strace的時候,無法阻塞到自己想要查看的條目,推薦使用pmap。

strace -f -e"brk,mmap,munmap" -p 2853 原因: 對 heap 的操作,操 作系統提供了 brk()函數,C 運行時庫提供了 sbrk()函數;對 mmap 映射區域的操作,操作系 統提供了 mmap()和 munmap()函數。sbrk(),brk() 或者 mmap() 都可以用來向我們的進程添 加額外的虛擬內存。Glibc 同樣是使用這些函數向操作系統申請虛擬內存。

e0196218-47ef-11ee-97a6-92fbcf53809c.png

查看JVM使用內存分配器類型

發現很大量為[anon](匿名地址)的64M內存空間被申請。通過附錄參考的一些文檔發現很多都提到64M的內存空間問題(glibc內存分配器導致的),抱著試試看的態度,準備看看是否為glibc。

cd /opt/taobao/java/bin
ldd java
e02705d0-47ef-11ee-97a6-92fbcf53809c.png

glibc為什么會有泄露

e05ba592-47ef-11ee-97a6-92fbcf53809c.png 我們當前使用的glibc的版本為2.17。說到這里可能簡單需要介紹一下glibc的發展史。

V1.0時代』Doug Lea Malloc 在Linux實現,但是在多線程中,存在多線程競爭同一個分配分配區(arena)的阻塞問題。

V2.0時代』Wolfram Gloger 在 Doug Lea 的基礎上改進使得 Glibc 的 malloc 可以支持多線程——ptmalloc。

glibc內存釋放機制(可能出現泄露時機)

調用free()時空閑內存塊可能放入 pool 中,不一定歸還給操作系統。

.收縮堆的條件是當前 free 的塊大小加上前后能合并 chunk 的大小大于 64KB、,并且 堆頂的大小達到閾值,才有可能收縮堆,把堆最頂端的空閑內存返回給操作系統。

『V2.0』為了支持多線程,多個線程可以從同一個分配區(arena)中分配內存,ptmalloc 假設線程 A 釋放掉一塊內存后,線程 B 會申請類似大小的內存,但是 A 釋放的內 存跟 B 需要的內存不一定完全相等,可能有一個小的誤差,就需要不停地對內存塊 作切割和合并。

e069d978-47ef-11ee-97a6-92fbcf53809c.png

為什么是64M

回到前面說的問題,為什么會創建這么多的64M的內存區域。這個跟glibc的內存分配器有關下的,間作介紹。 V2.0版本的glibc內存分配器,將分配區域分配主分配區(main arena)和非主分配區(non main arena)(在v1.0時代,只有一個主分配區,每次進行分配的時候,需要對主分配區進行加鎖,2.0支持了多線程,將分配區通過環形鏈表的方式進行管理),每一個分配區利用互斥鎖使線程對于該分配區的訪問互斥。

主分配區:可以通過sbrk/mmap進行分配。

非主分配區,只可以通過mmap進行分配。

其中,mmap每次申請內存的大小為HEAP_MAX_SIZE(32 位系統上默認為 1MB,64 位系統默 認為 64MB)。

哪里在泄露

既然知道了存在堆外內存泄露,就要查一下到低是什么地方的內存泄露。參考歷史資料,可以使用jemalloc工具進行排查。

配置dump內存工具(jemalloc)

由于系統裝載的是glibc,所以可以自己在不升級jdk的情況下編譯一個jemalloc。

github下載比較慢,上傳到oss,再做下載。


sudo yum install -y git gcc make graphviz 
    wget -P /home/admin/general-aftersales https://xxxx.oss-cn-zhangjiakou.aliyuncs.com/jemalloc-5.3.0.tar.bz2 &&  
    mkdir   /home/admin/general-aftersales/jemalloc && 
    cd  /home/admin/general-aftersales/ && 
    tar -jxcf  jemalloc-5.3.0.tar.bz2 && 
    cd  /home/admin/xxxxx/jemalloc-5.3.0/ && 
    ./configure  --enable-prof && 
    make && 
    sudo make install


export LD_PRELOAD=/usr/local/lib/libjemalloc.so.2  MALLOC_CONF="prof:true,lg_prof_interval:30,lg_prof_sample:17,prof_prefix:/home/admin/general-aftersales/prof_prefix

核心配置

make之后,需要啟用prof,否則會出現『: Invalid conf pair: prof:true』類似的關鍵字

配置環境變量

LD_PRELOAD 掛載本次編譯的庫

MALLOC_CONF 配置dump內存的時機。

"lg_prof_sample:N",平均每分配出 2^N 個字節 采一次樣。當 N = 0 時,意味著每次分配都采樣。

"lg_prof_interval:N",分配活動中,每流轉 1 ? 2^N 個字節,將采樣統計數據轉儲到文件。

重啟應用

./appctl restart

監控內存dump文件

如果上述配置成功,會在自己配置的prof_prefix 目錄中生成相應的dump文件。 然后將文件轉換為svg格式


jeprof --svg /opt/taobao/java/bin/java prof_prefix.36090.9.i9.heap > 36090.svg
然后就可以在瀏覽器中瀏覽了 e0838364-47ef-11ee-97a6-92fbcf53809c.png

與參閱文檔中結果一致,有通過Java java.util.zip.Inflater調用JNI申請內存,進而導致了內存泄露。

既然找到了哪里存在內存泄露,找到使用的地方就很簡單了。

發現元兇

通過arthas 的stack命令查看某個方法的調用棧。

statck java.util.zip.Inflater 

java.util.zip.InflaterInputStream

e120ec44-47ef-11ee-97a6-92fbcf53809c.pnge12c03e0-47ef-11ee-97a6-92fbcf53809c.png 如上源碼可以看出,如果使用InflaterInputStream(InputStream?in)?來構造對象usesDefaultInflater=true, 否則全部為false; 在流關閉的時候。 e1df5bac-47ef-11ee-97a6-92fbcf53809c.pnge263af92-47ef-11ee-97a6-92fbcf53809c.png

end()是native方法。

只有在『usesDefaultInflater=true』的時候,才會調用free()將內存歸嘗試歸還OS,依據上面的內存釋放機制,可能不會歸還,進而導致內存泄露。

comp.taobao.pandora.loader.jar.ZipInflaterInputStream

二方包掃描

e298f0c6-47ef-11ee-97a6-92fbcf53809c.png ZipInflaterInputStream 的流關閉使用的是父類java.util.zip.InflaterInputStream,構造器使用public?InflaterInputStream(InputStream?in,?Inflater?inf,?int?size) 這樣如上『usesDefaultInflater=false』,在關閉流的時候,不會調用end()方法,導致內存泄露。 com.taobao.pandora.loader.jar.ZipInflaterInputStream 源自pandora ,咨詢了相關負責人之后,發現2年前就已經修復此內存泄露問題了。

最低版本要求 sar包里的 pandora 版本,要大于等于 2.1.17

問題解決

升級ajdk版本

需要咨詢一下jdk團隊的同學,需要使用jemalloc作為內存分配器的版本。

升級pandora版本

如上所說,版本高于2.1.17即可。

我們是團隊是統一做的基礎鏡像,找相關的同學做了dockerfile from的升級。

發布部署&觀察

e2b4e18c-47ef-11ee-97a6-92fbcf53809c.pnge2dcdd0e-47ef-11ee-97a6-92fbcf53809c.pnge3003aba-47ef-11ee-97a6-92fbcf53809c.png 這此真的舒服了~ ?

總結

探究了glibc的工作原理之后,發現相比jemalloc的內存使用上確實存在高碎片率的問題,但是本次問題的根本還是在應用層面沒有正確的關閉流加劇的堆外內存的泄露。

總結的過程,也是學習的過程,上述分析過程歡迎評論探討。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內存
    +關注

    關注

    8

    文章

    3055

    瀏覽量

    74329
  • Glibc
    +關注

    關注

    0

    文章

    9

    瀏覽量

    7525
  • 內存泄露
    +關注

    關注

    0

    文章

    6

    瀏覽量

    2003

原文標題:實戰總結|記一次glibc導致的堆外內存泄露

文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    波特率漂移導致通信異常的故障排查過程

    示波器的協議解碼功能大家都不生疏,你是否有過波形看起來正常,協議參數、解碼設置都正確,卻無法正常解碼的經歷呢?本文以UART協議為例,分享由于波特率漂移導致通信異常的故障排查過程
    的頭像 發表于 01-08 13:51 ?6478次閱讀
    波特率漂移<b class='flag-5'>導致</b>通信異常的故障<b class='flag-5'>排查過程</b>

    Linux上對進程進行內存分析和內存泄漏定位

    內存申請,內存管理器使用brk系統調用擴展頂指針。M_MMAP_MAX是該進程中最多使用mmap分配地址段的數量。如果在實際的調試過程中,懷疑某處發生了
    發表于 07-09 08:15

    分享一種內存泄漏定位排查技巧

    常見的泄漏方式在嵌入式開發中,經常會使用malloc,free分配釋放內存,稍不小心就可能導致內存一點點地泄露,直至
    發表于 12-17 08:13

    如何有效地排查內存泄露的疑難問題

    不太輕易去改動里面的代碼,這無疑也增大了排查難度。在這樣的背景下,要完成從“復雜度”如此高的代碼里面找出可能出現【內存泄露】的幾行問題代碼,需要有點手段才行。3 解決思路根據多年對【
    發表于 09-01 14:47

    單片機C語言幾種內存泄露總結

    程序的設計的錯誤導致這部分內存沒有被釋放,那么此后這塊內存將不會被使用,就會產生Heap Leak. 這是最常見的內存泄露
    發表于 11-14 10:09 ?2591次閱讀
    單片機C語言幾種<b class='flag-5'>內存</b><b class='flag-5'>泄露</b>總結

    Java開發者必須了解的內存技術

    先來看一個 Demo:在 Demo 中分配內存用的是 allocateDirect 方法,但其內部調用的是 DirectByteBuffer,換言之,DirectByteBuffer 才是實際操作
    發表于 07-01 10:19 ?3799次閱讀
    Java開發者必須了解的<b class='flag-5'>堆</b><b class='flag-5'>外</b><b class='flag-5'>內存</b>技術

    DC-DC電源故障排查過程和總結,珍貴的經驗!資料下載

    電子發燒友網為你提供DC-DC電源故障排查過程和總結,珍貴的經驗!資料下載的電子資料下載,更有其他相關的電路圖、源代碼、課件教程、中文資料、英文資料、參考設計、用戶指南、解決方案等資料,希望可以幫助到廣大的電子工程師們。
    發表于 04-25 08:54 ?75次下載
    DC-DC電源故障<b class='flag-5'>排查過程</b>和總結,珍貴的經驗!資料下載

    glibc內存管理存在的共性問題及解決方法

    引言 對于嵌入式設備來說,用戶態內存管理是一項基礎功能,目前主流的用戶態內存管理庫有glibc、uclibc、tcmalloc、jemalloc等。 本文基于glibc2.17版本進行
    的頭像 發表于 06-18 14:50 ?3352次閱讀

    什么是內存內存是如何分配的?

    在一般的編譯系統中,內存的分配方向和棧內存是相反的。當棧內存從高地址向低地址增長的時候,內存
    的頭像 發表于 07-05 17:58 ?1w次閱讀

    Glibc內存管理之Ptmalloc2源代碼分析

    Glibc內存管理之Ptmalloc2源代碼分析
    發表于 07-29 09:20 ?24次下載

    Java內部類持有外部類導致內存泄露的原因以及其解決方案

    簡介 為什么要持有外部類 實例:持有外部類 實例:不持有外部類 實例:內存泄露 不會內存泄露的方案 簡介 「說明」 本文介紹 Java 內部類持有外部類
    的頭像 發表于 10-08 16:32 ?1016次閱讀

    mtrace分析內存泄露

    一、mtrace分析內存泄露 mtrace(memory trace),是 GNU Glibc 自帶的內存問題檢測工具,它可以用來協助定位內存
    的頭像 發表于 11-13 10:55 ?1375次閱讀
    mtrace分析<b class='flag-5'>內存</b><b class='flag-5'>泄露</b>

    內存是如何泄露

    作為 C++ 程序員,內存泄露始終是懸在頭上的一顆炸彈。在過去幾年的 C++ 開發過程中,由于我們采用了一些技術,我們的程序發生內存泄露的情
    的頭像 發表于 11-13 14:13 ?456次閱讀
    <b class='flag-5'>內存</b>是如何<b class='flag-5'>泄露</b>的

    java內存溢出排查方法

    Java內存溢出(Memory overflow)是指Java虛擬機(JVM)中的內存無法滿足對象分配的需求,導致程序拋出OutOfMemoryError異常。
    的頭像 發表于 11-23 14:46 ?3342次閱讀

    Java怎么排查oom異常

    據量的應用中。要排查OOM異常,需要經過以下幾個步驟: 理解OOM異常的原因:OOM異常通常有以下幾個原因:內存泄露內存溢出、內存不足以容
    的頭像 發表于 12-05 13:47 ?1288次閱讀
    棋牌室经营| 百家乐专打单跳投注法| 大发888娱乐场游戏| 网上百家乐公式| 治县。| 百家乐博欲乐城| 中国百家乐官网的玩法技巧和规则 | 沈丘县| 奥斯卡百家乐的玩法技巧和规则| 现金百家乐官网攻略| 大发888游戏下载官方下载| 百家乐全讯网2| 百家乐官网声音不印网| 大发888娱乐场怎样下载| 百家乐美女荷官| 百家乐官网电脑上怎么赌| 大发888我发财官网| 百家乐官网网哪一家做的最好呀| 大地娱乐城| 百家乐官网站| 木星百家乐官网的玩法技巧和规则| 花莲市| 威尼斯人娱乐场 澳门赌场| 百家乐磁力录| 百家乐官网游戏开发技术| 大发888娱乐网下 | 大发888收获| 七胜百家乐娱乐城总统网上娱乐城大都会娱乐城赌场 | 网络百家乐官网必胜投注方法| 娱乐城开户送金| 百家乐开户优惠多的平台是哪家| 现金百家乐官网网上娱乐| 大发888老虎机网页版| 澳门百家乐走势图怎么看| 金樽百家乐官网的玩法技巧和规则| 赣州市| 大发888m摩卡游戏 | 百家乐官网娱乐城官方网| 大三巴娱乐城开户| 百家乐在线娱乐平台| 请问下百家乐官网去哪个娱乐城玩最好呢 |