c c 程式記憶體洩漏跟蹤總結

2021-10-08 04:19:29 字數 2744 閱讀 3861

最近一段時間,伺服器頻繁出現記憶體增長嚴重,導致伺服器效能極具下降,由於伺服器**比較龐大,而且是線上問題,所以處理起來比較棘手,好在我通過一些手段定位到了bug的具體位置,故以記錄之。

由於是線上問題,所以像valgrind、gdb、memstack基本不適用,就算你是gdb高手,通過gdb adb attach pid 和gdb dump memory 也是不能很準確定位,而valgrind本身的消耗會影響別人測試或者除錯。

c/c++程式的記憶體洩漏,個人認為有幾種情況:

1、malloc、memalagin、realloc、calloc沒有free

2、給記憶體指標重新賦值

3、越界導致的記憶體指標被修改,這個更難,還得解決越界的問題。

4、函式返回的是動態記憶體指標,卻被忽視,如strdup函式

5、結構體本身是動態記憶體指標,結構體成員裡邊有動態指標,只釋放了結構體,沒有釋放成員。

6、第三方動態庫存在記憶體洩漏,這個比較麻煩,因為第三方庫沒有除錯資訊。但一般pmap能看一部分資訊。

我本人定位問題,其實也是比較笨的辦法,基本上是轉殖一台機器,設定相同的觸發條件,然後在後台除錯輸出,也用gdb和valgrind,效率不高。我們的線上問題是傳送端速度快,接收端速度慢,導致中間**層記憶體暴增。

一、mtrace

mtrace()函式為記憶體分配函式安裝鉤子函式(malloc、realloc、memalign、free)。 這些掛鉤函式記錄有關記憶體分配的跟蹤資訊和重新分配。 跟蹤資訊可用於發現記憶體洩漏並嘗試釋放程式中未分配的記憶體。

程式設計介面:

#include void mtrace(void);

void muntrace(void);

**實現:

#include int main(int argc, char **ar**)

執行程式之後,在程式的當前目錄下會生成output檔案,然後使用命令獲取堆疊資訊:

# mtrace 程式名 output檔案 >msg.txt

通過檢視msg.txt檔案,就可以找到記憶體洩漏的地方、大小,如:

memory not freed:

-----------------

address size caller

0x0000000001ed4760 0x18 at 0x7fface2c1780

0x0000000001ed47b0 0x18 at 0x7fface2c1780

0x0000000001ed59f0 0xb0 at 0x7fface2c1780

0x0000000001ed5ab0 0x18 at 0x7fface2c1780

0x0000000001ed5ad0 0x18 at 0x7fface2c1780

0x0000000001ed5af0 0x18 at 0x7fface2c1780

2、封裝malloc,輸出除錯資訊

封裝**:

void *my_malloc(int size, int zero,const char *file,int line,const char*func)

}printf("malloc %s:%d:%s:(%d):%p\n",file,line,func,size,rv);

return rv;

}void my_free(void *ptr,const char *file,int line,const char*func)

}

標頭檔案介面**

void *my_malloc(int size, int zero,const char *file,int line,const char*func);

void my_free(void *ptr,const char *file,int line,const char*func);

#define mem_free(ptr) my_free(ptr, __file__,__line__,__func__)

#define mem_malloc(size, zero) my_malloc((size), zero,__file__,__line__,__func__)

然後在測試的時候會出現很多呼叫mem_malloc和mem_free的輸出資訊,可以重定向到乙個日誌檔案,在程式結束時分析日誌檔案,主要找malloc的指標有沒有對應的free輸出。可以針對性的寫程式進行分析,雖然分析的過程比較慢,但如果分析出來,就能直接根據檔案、函式名、行號定位到具體位置。

3、在malloc和free的函式中寫記錄

在malloc中把指標值寫到快取中,free中把指標值delete掉。在寫指標的時候,需要把檔案、行號,函式名寫進去。這樣在程式結束的時候,把快取資料寫到檔案中,通過檢視檔案一目了然。

我個人認為在高效能伺服器的開發中,隨程式執行動態maloc和free是不可取的,而是要使用記憶體池。像nginx,redis這種高效能中介軟體,基本都是使用的記憶體池。記憶體池能夠很好的避免記憶體無限制增長,在排查問題的時候也比較好定位。

其實以上寫的內容在c++中,建構函式和析構函式也能用。如果是c語言,我建議還是在單元測試的時候使用valgrind和gdb除錯。

好的c語言程式,一定是合理利用記憶體,尤其在併發網路伺服器中,每個連線的記憶體資源分配決定了整體效能,像多執行緒比多程序的記憶體利用率高,但出問題會導致整個服務崩潰,那麼既要多程序的穩定性,又要多執行緒的效能,那麼使用協程就是好的解決辦法。

C C 程式記憶體洩漏檢測

c c 程式記憶體洩漏檢測 摺疊 1.包含標頭檔案和定義 define crtdbg map alloc include include 如果定義了 crtdbg map alloc,列印出來的是檔名和行數等更加直觀的資訊。2.方法一 在程式入口寫幾個語句 int tmpflag crtsetdbg...

C C 檢查記憶體洩漏

最近剛換工作,還在試用期,分配給我的也都是些零碎的任務。前陣子領導扔給我乙個小專案,這個專案底層使用c 編寫的3d渲染引擎,然後用cli包裝了一下,提供給上層的c 呼叫。這個專案存在比較嚴重的記憶體洩漏問題,由於目前公司寫c 的人寥寥無幾,寫c 的又不太懂如何檢測c 的記憶體洩漏,領導就把這個小任務...

C 程式記憶體洩漏

今天在vs2017下程式設計,遇到了未知的錯誤。debug平台是x32。用到了虛函式過載動態繫結,過載函式內部有定義區域性的vector變數。在函式結束之後,vector未自動銷毀,導致記憶體洩漏,程式崩潰。原因未知。2020 3 21 11 17 45 原因查明 自定義的vector類在使用lin...