在C語言編程裏,最常見的內存問題就是使用了malloc分配的內存,忘記釋放(free)造成的內存泄漏。今天介紹一個內存檢測工具Valgrind。
在Linux系統上,如Unbuntu安裝Valgrind:
apt-get install valgrind
我先寫一個內存泄漏的代碼,然後演示如何使用valgrind來找到泄漏點。
編譯帶調試信息的可執行文件
# gcc -g tt.c -o tt
-g 告訴 GCC 在編譯 / 鏈接過程中,將調試信息(Debug Information) 嵌入到生成的目標文件(.o)或可執行文件中。這些調試信息包括:
- 源代碼行號與機器指令的映射關係;
- 變量名、函數名、類型信息(不再被剝離);
- 源代碼文件路徑、函數參數 / 局部變量的存儲位置等。
- 沒有 -g 時,GCC 生成的可執行文件會默認剝離調試信息,僅保留運行所需的機器碼,此時用 gdb 調試只能看到彙編指令,無法關聯源代碼,也無法查看 / 修改變量。
使用valgrind檢測內存問題
valgrind --tool=memcheck ./tt
memcheck 是默認工具,可省略 --tool=memcheck。
valgrind ./tt
從上圖,我們知道,程序一共申請了2塊內存,釋放了一次,在程序退出時,還有一塊1字節內存沒有釋放。
memcheck 本質是一個 “內存檢測模擬器”,它會讓程序在 Valgrind 的虛擬 CPU 中運行,全程監控每一次內存操作(分配 / 釋放 / 訪問),能檢測出以下高頻問題:
- 內存泄漏 (Memory Leak) ,如malloc/new 分配後未 free/delete
- 數組 / 指針越界訪問 int a[5]; a[5] = 10;(訪問超出數組範圍)
- 使用未初始化的內存 int x; printf(“%d”, x);
- 重複釋放內存 free§; free§;
- 釋放後仍訪問內存 (野指針) free§; printf(“%d”, *p);
- 內存分配 / 釋放不匹配 new[] 分配卻用 delete 釋放
- 棧內存溢出,局部數組過大 / 遞歸過深導致棧越界
使用–leak-check=full查找泄漏點
從上面的信息,可知tt.c的第8行出了問題。