代碼中使用tcmalloc替換malloc
我們?nèi)绾问褂胻cmalloc來替換glibc的malloc呢?
在鏈接tcmalloc的時候我們可以使用以下任意一種方式:
1.啟動程序之前,預先加載tcmalloc動態(tài)庫的環(huán)境變量設置:exportLD_PRELOAD="
/usr/local/lib/libtcmalloc.so"
2.在你的動態(tài)庫鏈接的地方加入:-ltcmalloc
檢測內(nèi)存泄漏
測試代碼1:
#include < iostream >
using namespace std;
int main()
{
int *p = new int();
return 0;
}
編譯:g++ t.cpp -o main -ltcmalloc -g -O0
內(nèi)存泄漏檢查:env HEAPCHECK=normal ./main
結(jié)果:
root@ubuntu:/home/gaoke/test# env HEAPCHECK=normal ./main
WARNING: Perftools heap leak checker is active -- Performance may suffer
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 4 bytes in 1 objects
The 1 largest leaks:
*** WARNING: Cannot convert addresses to symbols in output below.
*** Reason: Cannot find 'pprof' (is PPROF_PATH set correctly?)
*** If you cannot fix this, try running pprof directly.
Leak of 4 bytes in 1 objects allocated from:
@ 4007ef
@ 7f7895a64f45
@ 400719
If the preceding stack traces are not enough to find the leaks, try running THIS shell command:
pprof ./main "/tmp/main.6712._main_-end.heap" --inuse_objects --lines --heapcheck --edgefraction=1e-10 --nodefraction=1e-10 --gv
If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more repeatably
Exiting with error code (instead of crashing) because of whole-program memory leaks
大家注意,這里有關鍵字Leak,你就得當心這里可能存在內(nèi)存泄漏,提示
Leak of 4 bytes in 1 objects allocated from
對,是有四字節(jié)的內(nèi)存泄漏,雖然你看代碼能看到指針p未釋放,但是這里你需要掌握的是在你無法直觀的通過閱讀代碼來找到內(nèi)存泄漏點的情況下,如何用tcmalloc工具來分析問題。
相信細心的你會注意到運行輸出的這一行
pprof ./main "/tmp/main.6712. main -end.heap" --inuse_objects --lines --heapcheck --edgefraction=1e-10 --nodefraction=1e-10 --gv
這里就是我要重點講的pprof工具
google-perftool提供了一個叫pprof的工具,它是一個perl的腳本,通過這個工具,可以將google-perftool的輸出結(jié)果分析得更為直觀,輸出為text、圖片、pdf等格式。
這里我們把結(jié)果通過text的方式輸出:你只需要把剛才的--gv換成--text
pprof ./main "/tmp/main.6712. main -end.heap" --inuse_objects --lines --heapcheck --edgefraction=1e-10 --nodefraction=1e-10 --text
好了,你可以看到這里已經(jīng)很明顯了,給你提示了t.cpp文件的第五行代碼存在內(nèi)存泄漏(當然你也可以輸出其他格式,raw,png,pdf等等,whatever,只要可以幫助你去分析問題解決問題)。
實際上項目中遇到的內(nèi)存泄漏問題是異常復雜的,我給的這個示例只是小試牛刀。項目常見的內(nèi)存泄漏點大家都清楚,new了但是沒有得到delete,但是要根據(jù)pprof工具對應的函數(shù),代碼行找到對應的泄漏點你可能需要花費點功夫。
實際上你的大多數(shù)應用都是以服務的方式啟動,長時間處于作業(yè)/工作狀態(tài)。你需要定期來檢測下內(nèi)存泄漏情況,那么這時你需要顯示的調(diào)用接口來輸出leak情況,
示例代碼2
bool memory_check(void* arg)
{
HeapLeakChecker::NoGlobalLeaks();
return TRUE;
}
將上面的代碼加到你的定時檢測邏輯里,或者需要觀察的點,那么他就會輸出示例1中的內(nèi)容,動態(tài)的幫助你分析內(nèi)存泄漏點。
分析使用tcmalloc后內(nèi)存暴漲不降問題
記得幾年前我開始推廣大家使用tcmalloc后,一些同事做壓測過程中也遇到了不少麻煩。比如當有大量數(shù)據(jù)過來,new出來很多的大塊內(nèi)存,突然發(fā)現(xiàn)有時候內(nèi)存增長到幾個G,開始以為是內(nèi)存泄露的問題。
先是用tcmalloc環(huán)境變量來檢查內(nèi)存泄漏沒有找到泄漏的報告,用valgrind也做了大量的測試,但是valgrind顯示沒有內(nèi)存泄露。 實際上遇到這種問題不要慌,基本上是對tcmalloc使用上的問題,你要知道默認情況下,tcmalloc會將長時間未用的內(nèi)存交還系統(tǒng)。tcmalloc_release_rate這個flag控制了這個交回頻率。你可以在運行時通過這個語句強制這個release發(fā)生:
MallocExtension::instance()->ReleaseFreeMemory();
當然了,你可以通過 SetMemoryReleaseRate() 來設置這個tcmalloc_release_rate. 如果設置為0,代表永遠不交回。數(shù)字越大代表交回的頻率越大。一般合理的值就是設置一個0 - 10 之間的一個數(shù)。也可以通過設置環(huán)境變量 TCMALLOC_RELEASE_RATE來設置這個rate。
實際上我估計很多人看了官網(wǎng)說的
MallocExtension::instance()->SetMemoryReleaseRate(7.0);
很疑惑,我曾經(jīng)帶著疑惑做了測試,發(fā)現(xiàn)SetMemoryReleaseRate設置9,10回收的內(nèi)存仍然是很慢的,所以后來我索性在進程啟動的開始設置SetMemoryReleaseRate為9,然后在new對象的時候ReleaseFreeMemory,在new對象析構(gòu)的時候ReleaseFreeMemory一次 (new出來的對象可能從new到delete的生命周期是不確定的,可能存在1天?4小時?30分鐘都有可能,而且不是頻繁的釋放和銷毀),因此這種情況下,內(nèi)存就比較及時的回收了,所以大家可以根據(jù)自己的項目邏輯來選擇ReleaseFreeMemory的時機,最好不要頻繁的申請和釋放,這對tcmalloc來說也是難受。
所以你不僅僅要關注tcmalloc申請大小內(nèi)存塊,還要關注內(nèi)存塊的在合適的時間及時回收,否則造成內(nèi)存占用過高。
-
內(nèi)存
+關注
關注
8文章
2978瀏覽量
73818 -
Glibc
+關注
關注
0文章
9瀏覽量
7491 -
動態(tài)庫
+關注
關注
0文章
16瀏覽量
6216 -
malloc
+關注
關注
0文章
52瀏覽量
64
發(fā)布評論請先 登錄
相關推薦
評論