Linux centos7 c++ 內存泄漏定位


最近被公司一個新產品的內存泄漏搞得焦頭爛額,該產品屬於主線代碼的一個分支,代碼大致相同,只是硬件很不一樣,但是主線卻沒有內存泄漏,分支每天都會有400M的泄漏,臨近過點,亞歷山大。

內存泄漏這次在操作系統層面總結下來分為四類:堆泄漏,棧堆積,系統資源泄漏,內存碎片

從出現概率來說逐漸降低,所以定位順序也依次展開

1.堆泄漏

  也就是new/malloc沒有對應釋放,這個一般來說直接用valgrind直接跑就完事,這里看到安裝valgrind網上大部分都是官網下載源碼到服務器編譯安裝,由於該產品glibc版本較低且沒有安裝gcc,也找不到配套的低版本的gcc,於是直接下載了valgrind的rpm包,直接拷到服務器安裝,一頓猛操作后發現,有打印一些明確泄漏的,但是最多幾個字節,剩余的可能泄漏點都是程序初始化申請的固定內存,不太可能造成每天幾百兆的泄漏。

  防止工具不給力,還在代碼里在幾個頻繁申請內存的地方加了引用計數,觀察到內存增長時引用計數也沒有增長,大概不是這個原因。

2.棧堆積

  可能時某個隊列積攢了大量數據導致的內存增長,但是增加打印觀察隊列數也沒有增長

3.系統資源泄漏

  有可能是線程句柄、套接字句柄、文件句柄沒有正常關閉,比較分支和主線代碼,發現有一處pthread_create后,線程結束后沒有回收資源,需要調用下pthread_deatch, 同步后跑了一晚還是有泄漏,繼續定位

4.內存碎片

  在內存增長后觀察日志時,突發奇想把業務開關關閉了,發現內存全部降了下來,降低到業務開始前的內存,這進一步證明沒有發生堆泄漏,偶然看到一篇帖子,glibc有內存空洞(碎片)的問題,看了下確實和我這個情況有點類似,glibc針對小內存有一套有自己的緩存管理,並且還有可能造成內存碎片無法釋放,大內存才會使用mmap,但系統調用消耗大一點

  之前有個大小為20字節的結構體因為很頻繁創建,為了避免頻繁觸發拷貝構造,每次都是new一下用完delete掉,認為效率會快一點,於是更改這一處new對象為直接從棧聲明對象,再跑一天發現內存不再增長。

  這里還是疑惑為什么主線版本也是同樣的代碼為什么沒有漏,看了新產品和主線的glibc版本,新產品是glibc-2.17.292,主線是glibc-2.17.196, 新產品還高一點,難道高版本引入了某些緩存釋放異常,精力有限,暫不深究。

 

后記:

  慘絕人寰,跑了兩天之后再次發生內存泄漏,太難了,無奈之下,只能自下而上注釋模塊代碼直接返回成功,編譯版本測試,又花了好幾天時間,最終層層注釋,發現到了注釋了某個模塊后內存不再增長,走讀了下代碼發現有個隊列只在析構時釋放了數據,正常情況下不停止任務不會析構,隊列就會一直增長,停止任務會觸發析構內存又會降,修改后再次跑應該是解決了,內存泄漏從出現概率上來看,分為常發型、偶發型、一次性、隱型,這次我這個總結來就是隱型的棧堆積導致。

  還有之前打印隊列數的時候沒有考慮周全,泄漏的這個庫沒考慮到,沒有打印它,失算失算。

  至於為什么valgrind沒有檢測出來隊列中的指針沒有釋放,大概是生成檢測報告時我都是讓程序正常退出的,退出的時候會觸發析構,所以檢測不出來,內存着實比cpu優化難搞。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM