替代系統(tǒng)自帶的malloc/new原因無(wú)非兩個(gè):
reason 1. 做內(nèi)存profile或查找問(wèn)題
reason 2. 自定義的分配方案提高性能
不過(guò)文章[1]中說(shuō)明了,替代全局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í)測(cè)中jemalloc可以
2. linux下C的程序可以用wrap的方式(相當(dāng)于python的decorator)
編譯加上選項(xiàng):gcc -Wl,-wrap,malloc
可以做到對(duì)malloc這個(gè)函數(shù),linker會(huì)調(diào)用__wrap_malloc代替之, 若要調(diào)用原來(lái)的malloc函數(shù)__real_malloc
缺點(diǎn):依賴于編譯器支持; 對(duì)c++的new不起作用 --> 不實(shí)用
啟示:這個(gè)方法作為function裝飾器,對(duì)于調(diào)試別的問(wèn)題倒有幫助。(例如不改變函數(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變量保存起來(lái)使用,并恢復(fù)現(xiàn)場(chǎng))
4. LD_PRELOAD注入.so ,替代原
環(huán)境變量LD_PRELOAD指定程序運(yùn)行時(shí)優(yōu)先加載的動(dòng)態(tài)連接庫(kù),這個(gè)動(dòng)態(tài)鏈接庫(kù)中的符號(hào)優(yōu)先級(jí)是最高的。標(biāo)準(zhǔn)C的各種函數(shù)都是存放在libc.so.6的文件中,在程序運(yùn)行時(shí)自動(dòng)鏈接。使用LD_PRELOAD后,自己編寫(xiě)的malloc的加載順序高于glibc中的malloc,這樣就實(shí)現(xiàn)了替換。用法 LD_PRELOAD=" ./mymalloc.so"
缺點(diǎn):在生產(chǎn)環(huán)境不現(xiàn)實(shí)。因?yàn)長(zhǎng)D_PRELOAD相當(dāng)于庫(kù)注入,有安全性問(wèn)題,是必須禁止的。(生產(chǎn)環(huán)境很多時(shí)候用-static連接)
5. 用宏或另外的函數(shù)替代new/malloc
比如定義一個(gè)宏或者指定的函數(shù),規(guī)定所有的分配釋放都調(diào)用他。這樣相當(dāng)于給項(xiàng)目引入了額外的代碼規(guī)則(而且是一立項(xiàng)就要遵循這個(gè)規(guī)則,否則該方法無(wú)效),不能很自然的new/delete, 如果分配和釋放調(diào)用得不一致,會(huì)產(chǎn)生問(wèn)題的。某產(chǎn)品組就是用宏,然后加上__FILE__, __LINE__之類的信息。
有時(shí)候valgrind的效率是個(gè)問(wèn)題(尤其生產(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的替代品:
自己寫(xiě)一個(gè)malloc其實(shí)很復(fù)雜,要考慮線程安全等各種問(wèn)題,性能到頭來(lái)可能更差。google 的tcmalloc, facebook使用的jemalloc. 多線程下性能較好,可以考慮使用。
缺點(diǎn):筆者嘗試過(guò)。tcmalloc不能正確用valgrind,只能用自帶gperftools(運(yùn)行中會(huì)core)
jemalloc可以使用valgrind,不過(guò)還沒(méi)完全驗(yàn)證是否都準(zhǔn)確。
tcmalloc相關(guān):
在64位系統(tǒng)上要裝libunwind, 對(duì)x86-64架構(gòu)使用還有些問(wèn)題
源碼包的INSTALL文檔里面也提到了這個(gè)問(wèn)題。
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è)庫(kù),這個(gè)庫(kù)又有版本問(wèn)題,各種囧啊....
筆者試過(guò)系統(tǒng)x86-64, freebsd,用靜態(tài)鏈接。實(shí)際用了一下,問(wèn)題很多很折騰,等他fix了再說(shuō)吧.
windows下可以參考:
jemalloc暫時(shí)未發(fā)現(xiàn)有什么兼容性問(wèn)題,運(yùn)行得挺好的。