概述
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架构的静态库,目前是个难题,烦请哪位大神给予指导!
来源:oschina
链接:https://my.oschina.net/u/4401649/blog/3401226