概述
TCMalloc 是 Google 開發的內存分配器,在不少項目中都有使用,例如在 Golang 中就使用了類似的算法進行內存分配。它具有現代化內存分配器的基本特征:對抗內存碎片、在多核處理器能夠 scale。據稱,它的內存分配速度是 glibc2.3(glibc是GNU發布的libc庫,即c運行庫。glibc是linux系統中最底層的api,幾乎其它任何運行庫都會依賴於glibc。glibc除了封裝linux操作系統所提供的系統服務外,它本身也提供了許多其它一些必要功能服務的實現)中實現的 malloc的數倍。
TCMalloc全稱Thread-Caching Malloc,即線程緩存的malloc,實現了高效的多線程內存管理,用於替代系統的內存分配相關的函數(malloc、free,new,new[]等)。
TCMalloc是gperftools的一部分,除TCMalloc外,gperftools還包括heap-checker、heap-profiler和cpu-profiler。本文只討論gperftools的TCMalloc部分。
git倉庫:https://github.com/gperftools/gperftools.git
官方介紹:https://gperftools.github.io/gperftools/TCMalloc.html
安裝
從git倉庫clone版本的gperftools的安裝依賴autoconf、automake、libtool,以Mac為例:
$ brew install autoconf automake libtool
Autoconf實際上是一個工具集,其中包含aclocal、autoheader和autoconf等可執行文件。Libtool軟件包是第三個重要的GNU工具,它的作用是確定共享庫在特定平台上的特性。
$ ./autogen.sh
生成Makefile
$ ./configure
編譯
$ make
安裝
$ make install
默認安裝在/usr/local/下的相關路徑(bin、lib、share),可在configure時以--prefix=PATH指定其他路徑。
TCMalloc是如何生效的
為什么指定-ltcmalloc或者與libtcmalloc_and_profiler.a連接之后,對malloc、free、new、delete等的調用就由默認的libc中的函數調用變為TCMalloc中相應的函數調用了呢?答案在libc_override.h中
Qt工程中使用tcmalloc,新建工程qtTCmallocTest,pro文件中鏈接靜態庫libtcmalloc.a或者動態庫libtcmalloc.dylib,我使用Mac平台的clang構建正常,運行也正常,Demo運行截圖如下圖所示,一切都好!
我使用iOS Simulator構建出現警告錯誤:
:-1: warning: URGENT:building for iOS Simulator simulator, but linking against dylib (/usr/local/lib/libtcmalloc.dylib) built for macOS. Note: This will be an error in the future.
實際運行也會有運行時的類似提示導致最終無法在iOS模擬器上運行:
解決辦法:重新編譯配置
$make uninstall // 刪除/usr/local/lib下的tcmalloc庫
$make clean // 清除make產生的臨時文件
// 重新configure來配置,只生成minimal的靜態庫(.a)
$./configure --disable-cpu-profiler --disable-heap-profiler --disable-heap-checker --enable-minimal --enable-static --disable-shared
$make & make install
編譯安裝成后后
$cd /usr/local/lib
$ls
可見只生成了libtcmalloc_minimal.a和libtcmalloc_minimal_debug.a
查看靜態庫的架構:
$lipo –info libtcmalloc_minimal.a
可見是x86_64架構的靜態庫,我們的iOS模擬器是64位處理器,測試需要x86_64架構庫,看起來可以使用的。
現在重新在Qt Creator中使用iOS Simulator構建我們上面的qtTCmallocTest Demo,在pro文件中添加靜態庫libtcmalloc_minimal.a,編譯鏈接,結果成功構建,運行時卻出錯了~
錯誤提示在tcmalloc的源碼中,嘗試free了已經失效的指針導致出錯。可能的原因是程序啟動后會調用glibc內存分配的malloc、free等函數,而tcmalloc庫就已經將glibc中的內存分配替換成了自己的,此時有點過早調用導致出錯。
解決:注釋修改tcmalloc源碼相關部分,然后再重新make以及make install
找到libc_override_osx.h,注釋部分代碼
重新make過程中還會出現如下錯誤:
可以看到是cfree和pvalloc引用錯誤,找到tcmalloc_unittest.cc可以看到如下代碼:
#if defined(_WIN32)
# define cfree free // don't bother to try to test these obsolete fns
# define valloc malloc
# define pvalloc malloc
將該文件中用到cfree的地方用free替代,用到valloc和pvalloc的地方用malloc替代,保存后,再重新make,沒啥錯誤,緊接着make install。
再次構建Demo,並運行:
注意:手機等嵌入式內存等較小,程序中不宜不斷申請內存,可能造成內存不夠用導致程序崩潰退出。
到此為止,使用tcmalloc靜態庫嘗試可以在iOS模擬器上運行了~
但是我在iOS真機上編譯時卻提示找不到arm64架構符號的錯誤:
可見在Mac OS的終端中執行的./configure & make & make install等操作編譯出來的靜態庫和動態庫是針對Mac平台的,iOS平台不兼容導致無法使用。
該文章指出:iOS用不了谷歌的tcmalloc,無語了~
Compile tcmalloc for iOS,but getting errors進行了Compile tcmalloc for iOS的嘗試,但是遇到了錯誤,看底下評論,這一部分在官網文檔中並沒有涉及,也希望借此機會來完善tcmalloc對iOS的支持。
我努力嘗試Clang交叉編譯iOS真機版本的tcmalloc,最終沒有編譯出可以正常使用的arm64架構的靜態庫,目前是個難題,煩請哪位大神給予指導!