C++不用工具,如何檢測內存泄漏?

不用工具指不用專門監測內存泄漏的工具,gdb隨便用。面試題,當時跪了,沒想到什麼好的解決方法。

相關問題:c++怎麼檢測內存泄露,怎麼定位內存泄露?


一個貌似可行的方案:對malloc進行mock, 利用ld的--wrap參數:

--wrap=symbol
Use a wrapper function for symbol. Any undefined reference to
symbol will be resolved to "__wrap_symbol". Any undefined
reference to "__real_symbol" will be resolved to symbol.

This can be used to provide a wrapper for a system function. The
wrapper function should be called "__wrap_symbol". If it wishes to
call the system function, it should call "__real_symbol".

Here is a trivial example:

void *
__wrap_malloc (size_t c)
{
void *ptr = __real_malloc (c);;
/**&< 在這裡記錄下ptr的值(將其存入容器) */ return ptr; } If you link other code with this file using --wrap malloc, then all calls to "malloc" will call the function "__wrap_malloc" instead. The call to "__real_malloc" in "__wrap_malloc" will call the real "malloc" function. You may wish to provide a "__real_malloc" function as well, so that links without the --wrap option will succeed. If you do this, you should not put the definition of "__real_malloc" in the same file as "__wrap_malloc"; if you do, the assembler may resolve the call before the linker has a chance to wrap it to "malloc". 然後將類似的方法應用到malloc相關的其他函數上(比如free) ----以上參考自 @陳碩 的blog (http://blog.csdn.net/Solstice/article/details/6423342)


2015-04-27

試試這個:

MemTrack: Tracking Memory Allocations in C++

2015-05-08

HLLib/DebugMemory.h at master · Rupan/HLLib · GitHub

2015-05-14

CZMQ 中定義了一個宏 zmalloc:czmq/czmq_prelude.h at master · zeromq/czmq · GitHub,配合 mtrace 來實現內存泄漏的檢測。

2015-08-13

http://dmalloc.com/

2017-10-15T14:10+08:00

https://github.com/abseil/abseil-cpp/tree/master/absl/debugging

---


說簡單也簡單,說複雜也複雜,曾經在PC QQ團隊負責性能優化的時候團隊解決過各種泄漏,內核對象句柄泄漏,GDI泄漏,內存泄漏等,解決的前提是先定位問題,然而這個定位問題就是檢測問題了,我們所有內部工具都是自己開發,主要還是運用二進位插樁,記錄資源的申請和釋放操作,然後對記錄進行匹配剔除,最後就是剩下的泄漏的了。

大致原理類似這裡:句柄泄漏檢測工具的實現原理

具體點就是,hook內存分配和釋放函數,然後記錄分配的內存的各項數據,以及本次操作的調用棧,後面就是處理數據了,最終通過泄漏的操作記錄下來的調用棧結合symbol文件定位到具體源碼的代碼行。


1:你在內存分配器前面套一層,記錄所有的分配和釋放,然後就可以在程序退出的時候知道有哪些內存沒有釋放。

2:從JUCE學來的,用一個LeakDetector在你的類裡面標記:在你需要檢查的類裡面放一個宏,那個宏只在Debug編譯下生效,會在你的類里放一個額外的LeakDetector成員。這個LeakDetector對象在構造的時候,會往一個全局鏈表裡放一個節點;然後在析構的時候,會撤出那個節點。然後有一個全局對象,會在程序退出的時候列印自己還有哪些節點,即是泄漏的對象。

當然,實際上的內存檢查器遠遠比這個複雜。比如valgrind,它還會檢查你所有的訪問是否越界,並且可以不彙報那些雖然沒有釋放,但仍然reachable的堆內存(這很有可能不是泄漏而是懶得釋放)。


efficios/memleak-finder · GitHub 這個庫比較小可以參考。不過這個沒有hook的不是很全,有些case不能完全搞定。


不使用現成的工具,只能自己開發工具。

在linux上,我自己做過一個這樣的工具,思路很簡單,實現一個malloc/free等函數的動態庫,在啟動程序的時候用LD_PRELOAD方式優先載入該動態庫,這樣系統的malloc/free就會被我自己的代碼給接管,然後可以在我自己的malloc/free裡邊做內存分配的統計,這個動態庫同時也打開了一個HTTP埠(在第一次調用到malloc的時候),在程序運行期間,內存分配的統計結果可以通過網頁查詢。

這個工具一直在我們公司內部使用,效果相當好。


一種簡單的方法,看 nwa 的源代碼:Stones of Nvwa download, 就是這樣做的。

思路就是重載 malloc/free,new/delete 在實際申請的每個內存塊包一層,然後用一個鏈表他們鏈起來,調用一次 free 或者 delete ,就把改節點刪除。程序運行結束後遍歷鏈表就是內存泄露的部分。

另外一種方法就是利用操作系統 HOOK,Visual Leak Detector for Visual C++ 2008/2010/2012/2013


開任務管理器看內存佔用率算不算


看完了以上的答案以後,一個感覺,很玄乎、不實用。取決於你的涉獵面,而不是你的思考。

站在面試官的角度,這些冷僻的做法,是不可取的。

一是有學習成本,不能立馬上手解決問題;二是不通用,換個平台換個場景可能就無法復用了。

其實答案很簡單,無非就看你平時是否用心調試了:

在每一處申請/釋放內存的地方進行打點,然後匹對一下就知道哪裡內存泄露了。

例如:

A()

{

xx = malloc();

printf("malloc: %p
", xx); // 直接列印該地址或者記錄到debug日誌

}

B()

{

free(xx);

printf("free: %p
", xx); // 直接列印該地址或者記錄到debug日誌

}

這是最基本的原理,有很多變種,例如申請和釋放的次數是否一樣等。

基本上這樣就回答到點上了。

對於封裝的函數,例如C() 調用上面的A() ,一樣的,只需要在C()裡面打點即可;如果你能再這麼補充一下,這個答案就是103分了。


估計唯一的方法就是人工了吧,不過我是能靠程序解決的絕不靠人解決!


推薦閱讀:

生物信息學需要掌握C++嗎?
如何實現一個C++反射庫?
如何勸說上級更新 GCC 和 VS 的版本,並把項目遷移至 C++11?
關於C++虛函數表構造?

TAG:C | 內存泄露 | 軟體調試 | GDB |