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++虛函數表構造?