替代系統(tǒng)自帶的malloc/new原因無非兩個(gè):
reason 1. 做內(nèi)存profile或查找問題
reason 2. 自定義的分配方案提高性能
不過文章[1]中說明了,替代全局new不是一個(gè)好做法. 其實(shí)要達(dá)到以上兩點(diǎn)目的,筆者認(rèn)為用valgrind工具鏈就可以了。
解決方案:
1. 用valgrind和massif
valgrind的memcheck做內(nèi)存泄露和bug的查找, 里面的massif工具包做內(nèi)存性能profile, 足矣。比自己山寨的一個(gè)profiler要好。
注意:tcmalloc目前還不能很好支持valgrind, 實(shí)測中jemalloc可以
2. linux下C的程序可以用wrap的方式(相當(dāng)于python的decorator)
編譯加上選項(xiàng):gcc -Wl,-wrap,malloc
可以做到對malloc這個(gè)函數(shù),linker會調(diào)用__wrap_malloc代替之, 若要調(diào)用原來的malloc函數(shù)__real_malloc
缺點(diǎn):依賴于編譯器支持; 對c++的new不起作用 --> 不實(shí)用
啟示:這個(gè)方法作為function裝飾器,對于調(diào)試別的問題倒有幫助。(例如不改變函數(shù)的情況下,wrap一層,輸出些調(diào)試信息)
3. 用__malloc_hook
#include <malloc.h>
void *(*__malloc_hook)(size_t size, const void *caller);
缺點(diǎn):依賴GNU編譯工具鏈; 容易死循環(huán)(想利用原有malloc,要參考例子中,把原__malloc_hook變量保存起來使用,并恢復(fù)現(xiàn)場)
4. LD_PRELOAD注入.so ,替代原
環(huán)境變量LD_PRELOAD指定程序運(yùn)行時(shí)優(yōu)先加載的動態(tài)連接庫,這個(gè)動態(tài)鏈接庫中的符號優(yōu)先級是最高的。標(biāo)準(zhǔn)C的各種函數(shù)都是存放在libc.so.6的文件中,在程序運(yùn)行時(shí)自動鏈接。使用LD_PRELOAD后,自己編寫的malloc的加載順序高于glibc中的malloc,這樣就實(shí)現(xiàn)了替換。用法 LD_PRELOAD=" ./mymalloc.so"
缺點(diǎn):在生產(chǎn)環(huán)境不現(xiàn)實(shí)。因?yàn)長D_PRELOAD相當(dāng)于庫注入,有安全性問題,是必須禁止的。(生產(chǎn)環(huán)境很多時(shí)候用-static連接)
5. 用宏或另外的函數(shù)替代new/malloc
比如定義一個(gè)宏或者指定的函數(shù),規(guī)定所有的分配釋放都調(diào)用他。這樣相當(dāng)于給項(xiàng)目引入了額外的代碼規(guī)則(而且是一立項(xiàng)就要遵循這個(gè)規(guī)則,否則該方法無效),不能很自然的new/delete, 如果分配和釋放調(diào)用得不一致,會產(chǎn)生問題的。某產(chǎn)品組就是用宏,然后加上__FILE__, __LINE__之類的信息。
有時(shí)候valgrind的效率是個(gè)問題(尤其生產(chǎn)環(huán)境),這種方案有其價(jià)值所在, 就是代碼看上去比較ugly罷了
用宏的例子:
#define _New(Type, Catergory) (Type*)MyMemController::New((new Type), #Type, 1, sizeof(Type), Catergory, __FILE__, __LINE__, false)
#define _NewArray(Type, N, Catergory) (Type*)MyMemController::New((new Type[N]), #Type, N, sizeof(Type)*(N), Catergory, __FILE__, __LINE__, true)
MALLOC的替代品:
自己寫一個(gè)malloc其實(shí)很復(fù)雜,要考慮線程安全等各種問題,性能到頭來可能更差。google 的tcmalloc, facebook使用的jemalloc. 多線程下性能較好,可以考慮使用。
缺點(diǎn):筆者嘗試過。tcmalloc不能正確用valgrind,只能用自帶gperftools(運(yùn)行中會core)
jemalloc可以使用valgrind,不過還沒完全驗(yàn)證是否都準(zhǔn)確。
tcmalloc相關(guān):
在64位系統(tǒng)上要裝libunwind, 對x86-64架構(gòu)使用還有些問題
源碼包的INSTALL文檔里面也提到了這個(gè)問題。
CAUTION: if you install libunwind from the url above, be aware that
you may have trouble if you try to statically link your binary with
perftools: that is, if you link with 'gcc -static -lgcc_eh ...'.
This is because both libunwind and libgcc implement the same C++
exception handling APIs, but they implement them differently on
some platforms. This is not likely to be a problem on ia64, but
may be on x86-64.
主要是64位機(jī)frame-pointer的影響, 他的profile工具里的backtrace用libunwind這個(gè)庫,這個(gè)庫又有版本問題,各種囧啊....
筆者試過系統(tǒng)x86-64, freebsd,用靜態(tài)鏈接。實(shí)際用了一下,問題很多很折騰,等他fix了再說吧.
windows下可以參考:
jemalloc暫時(shí)未發(fā)現(xiàn)有什么兼容性問題,運(yùn)行得挺好的。