TCMalloc(Thread-Caching Malloc,线程缓存的malloc)是Google开发的内存分配算法库,最初做为Google性能工具库 perftools 的一部分,提供高效的多线程内存管理实现,用于替代操做系统的内存分配相关的函数(malloc、free,new,new[]等),具备减小内存碎片、适用于多核、更好的并行性支持等特性。
TCMalloc属于gperftools,gperftools项目包括heap-checker、heap-profiler、cpu-profiler、TCMalloc等组件。
gperftools源码地址:
https://github.com/gperftools/gperftools
TCMalloc源码地址:
https://github.com/google/tcmalloc前端
(1)TCMalloc源码安装
bazel源增长:
/etc/yum.repos.d/bazel.repoc++
[copr:copr.fedorainfracloud.org:vbatts:bazel] name=Copr repo for bazel owned by vbatts baseurl=https://download.copr.fedorainfracloud.org/results/vbatts/bazel/epel-7-$basearch/ type=rpm-md skip_if_unavailable=True gpgcheck=1 gpgkey=https://download.copr.fedorainfracloud.org/results/vbatts/bazel/pubkey.gpg repo_gpgcheck=0 enabled=1 enabled_metadata=1
在线安装bazel:yum install bazel3
TCMalloc源码下载:git
git clone https://github.com/google/tcmalloc.git cd tcmalloc && bazel test //tcmalloc/...
因为TCMalloc依赖gcc 9.2+,clang 9.0+: -std=c++17,所以推荐使用其它方式安装。github
gperftools源码下载:git clone https://github.com/gperftools/gperftools.git
生成构建工具:autogen.sh
配置编译选项:configure --disable-debugalloc --enable-minimal
编译:make -j4
安装:make install
TCMalloc库安装在/usr/local/lib目录下。
(3)在线安装
epel源安装:yum install -y epel-release
gperftools安装:yum install -y gperftools.x86_64
算法
在Linux64位系统环境下,gperftools使用glibc内置的stack-unwinder可能会引起死锁,所以官方推荐在配置和安装gperftools前,先安装libunwind-0.99-beta。
在Linux64位系统上使用libunwind只能使用TCMalloc,但heap-checker、heap-profiler和cpu-profiler不能正常使用。
若是不但愿安装libunwind,也能够用gperftools内置的stack unwinder,但须要应用程序、TCMalloc库、系统库(好比libc)在编译时开启帧指针(frame pointer)选项。
在x86-64下,编译时开启帧指针选项并非默认行为。所以须要指定-fno-omit-frame-pointer编译全部应用程序,而后在configure时经过--enable-frame-pointers选项使用内置的gperftools stack unwinder。后端
Front-end(前端):负责提供快速分配和重分配内存给应用,由Per-thread cache和Per-CPU cache两部分组成。
Middle-end(中台):负责给Front-end提供缓存。当Front-end缓存内存不够用时,从Middle-end申请内存。
Back-end(后端):负责从操做系统获取内存,并给Middle-end提供缓存使用。
TCMalloc中每一个线程都有独立的线程缓存ThreadCache,线程的内存分配请求会向ThreadCache申请,ThreadCache内存不够用会向CentralCache申请,CentralCache内存不够用时会向PageHeap申请,PageHeap不够用就会向OS操做系统申请。
TCMalloc将整个虚拟内存空间划分为n个同等大小的Page,将n个连续的page链接在一块儿组成一个Span;PageHeap向OS申请内存,申请的span可能只有一个page,也可能有n个page。
(1)Page
Page是操做系统对内存管理的单位,TCMalloc中以Page为单位管理内存,Page默认大小为8KB,一般为Linux系统中Page大小的倍数关系,如八、3二、64,能够在编译选项配置时经过--with-tcmalloc-pagesize参数指定。
Page越大,TCMalloc的速度相对越快,但其占用的内存也会越高。默认Page大小经过减小内存碎片来最小化内存使用,使用更大的Page则会带来更多的内存碎片,但速度上会有所提高。
(2)Span
Span是PageHeap中管理内存Page的单位,由一个或多个连续的Page组成,好比2个Page组成的span,多个span使用链表来管理,TCMalloc以Span为单位向操做系统申请内存。
第1个span包含2个page,第2个和第4个span包含3个page,第3个span包含5个page。
Span会记录起始page的PageID(start)以及所包含page的数量(length)。
Span要么被拆分红多个相同size class的小对象用于小对象分配,要么做为一个总体用于中对象或大对象分配。看成用做小对象分配时,span的sizeclass成员变量记录了其对应的size class。
span中包含两个Span类型的指针(prev,next),用于将多个span以链表的形式存储。
Span有三种状态:IN_USE、ON_NORMAL_FREELIST、ON_RETURNED_FREELIST。
IN_USE是正在使用中,要么被拆分红小对象分配给CentralCache或者ThreadCache,要么已经分配给应用程序。
ON_NORMAL_FREELIST是空闲状态。
ON_RETURNED_FREELIST指span对应的内存已经被PageHeap释放给系统。
(3)ThreadCache
ThreadCache是每一个线程独立拥有的Cache,包含多个空闲内存链表(size classes),每个链表(size-class)都有大小相同的object。
线程能够从各自Thread Cache的FreeList获取对象,不须要加锁,因此速度很快。若是ThreadCache的FreeList为空,须要从CentralCache中的CentralFreeList中获取若干个object到ThreadCache对应的size class列表中,而后再取出其中一个object返回。
(4)Size Class
TCMalloc定义了不少个size class,每一个size class都维护了一个可分配的FreeList,FreeList中的每一项称为一个object,同一个size-class的FreeList中每一个object大小相同。
在申请小内存时(小于256K),TCMalloc会根据申请内存大小映射到某个size-class中。好比,申请0到8个字节的大小时,会被映射到size-class1中,分配8个字节大小;申请9到16字节大小时,会被映射到size-class2中,分配16个字节大小,以此类推。
(5)CentralCache
CentralCache是ThreadCache的缓存,ThreadCache内存不足时会向CentralCache申请。CentralCache本质是一组CentralFreeList,链表数量和ThreadCache数量相同。ThreadCache中内存过多时,能够放回CentralCache中。
若是CentralFreeList中的object不够,CentralFreeList会向PageHeap申请一连串由Span组成的Page,并将申请的Page切割成一系列的object后,再将部分object转移给ThreadCache。
当申请的内存大于256K时,不在经过ThreadCache分配,而是经过PageHeap直接分配大内存。
(6)PageHeap
PageHeap保存存储Span的若干链表,CentralCache内存不足时,能够从PageHeap获取Span,而后把Span切割成object。
PageHeap申请内存时按照Page申请,但管理内存的基本单位是Span,Span表明若干连续Page。
PageHeap组织结构以下:数组
Front-end处理对特定大小内存的请求,有一个内存缓存用于分配或保存空闲内存。Front-end缓存一次只能由单个线程访问,不须要任何锁,所以大多数分配和释放都很快。
只要有适当大小的缓存内存,Front-end将知足任何请求。若是特定大小的缓存为空,Front-end将从Middle-end请求一批内存来填充缓存。Middle-end包括CentralfReelList和TransferCache。
若是Middle-end内存耗尽,或者用户请求的内存大小大于Front-end缓存的最大值,则请求将转到Back-end,以知足大块内存分配,或从新填充Middle-end的缓存。Back-end也称为PageHeap。
Front-end由两种不一样的实现模式:
(1)Per-thread
TCMalloc最初支持对象的Per-thread缓存,但会致使内存占用随着线程数增长而增长。现代应用程序可能有大量的线程,会致使每一个线程占用内存累积起来很大,也可能会致使由单个较小线程缓存累积起来的内存占用会很大。
(2)Per-CPU
TCMalloc近期开始支持Per-CPU模式。在Per-CPU模式下,系统中的每一个逻辑CPU都有本身的缓存,能够从中分配内存。在x86架构,逻辑CPU至关于一个超线程。缓存
Middle-end负责向Front-end提供内存并将内存返回Back-end。Middle-end由Transfer cache和Central free list组成,每一个类大小都有一个Transfer cache和一个Central free list。缓存由互斥锁保护,所以访问缓存会产生串行化成本。
(1)Transfer cache
当Front-end请求内存或返回内存时,将访问Transfer cache。
Transfer cache保存一个指向空闲内存的指针数组,能够快速地将对象移动到数组中,或者表明Front-end从数组中获取对象。
当一个线程正在分配另外一个线程释放的内存时,Transfer cache就能够获得内存名称。Transfer cache容许内存在两个不一样的线程之间快速流动。
若是Transfer cache没法知足内存请求,或者没有足够的空间容纳返回的对象,Transfer cache将访问Central free list。
(2)Central Free List
Central Free List使用spans管理内存,span是一个或多个TCMalloc内存Page的集合。
一个或多个对象的内存请求由Central Free List来知足,方法是从span中提取对象,直到知足请求为止。若是span中没有足够的可用对象,则会从Back-end请求更多的span。
当对象返回到Central Free List时,每一个对象都映射到其所属的span(使用pagemap,而后释放到span中)。若是驻留在指定span中的全部对象都返回给span,则整个span将返回给Back-end。性能优化
TCMalloc中Back-end有三项职责:
(1)管理大量未使用的内存块。
(2)负责在没有合适大小的内存来知足分配请求时从操做系统获取内存。
(3)负责将不须要的内存返回给操做系统。
TCMalloc有两种Back-end:
(1)Legacy Pageheap,管理TCMalloc中Page大小的内存块。
Legacy Pageheap是一个可用内存连续页面的特定长度的空闲列表数组。对于k<256
,kth条目是由k个TCMalloc页组成的运行的免费列表。第256项是长度大于等于256页的运行的免费列表
(2)支持hugepage的pageheap,以hugepage大小的内存块来管理内存。管理hugepage内存块中内存,使分配器可以经过减小TLB未命中率来提升应用程序性能。多线程
TCMalloc按照所分配内存的大小将内存分配分为三类:小对象分配(0, 256KB]、中对象分配(256KB, 1MB]、大对象分配(1MB, +∞)。
TCMalloc分配小对象分配时,在应用程序和内存之间其实有三层缓存:PageHeap、CentralCache、ThreadCache;TCMalloc分配中对象和大对象时,只有PageHeap缓存。
(1)Size Class
对于小于256KB的小对象,TCMalloc按大小划分85个类别(Size Class),每一个size class都对应一个大小,好比8字节,16字节,32字节。应用程序申请内存时,TCMalloc会首先将所申请的内存大小向上取整到size class的大小,好比1~8字节之间的内存申请都会分配8字节,9~16字节之间都会分配16字节,以此类推。
(2)ThreadCache
TCMalloc为每一个线程保存独立的线程缓存,称为ThreadCache。ThreadCache中对于每一个size class都有一个独立的FreeList,缓存n个未被应用程序使用的空闲对象。
TCMalloc对于小对象的分配直接从ThreadCache的FreeList中返回一个空闲对象,小对象的回收也将其从新放回ThreadCache中对应的FreeList中。因为每一个线程的ThreadCache是独立的,所以从ThreadCache中取用或回收内存是不须要加锁的,速度很快。
为了方便统计数据,各线程的ThreadCache链接成一个双向链表。ThreadCache结构以下:
(3)CentralCache
ThreadCache中的空闲对象来自全部线程的公用缓存CentralCache。CentralCache中对于每一个size class也都有一个单独的链表来缓存空闲对象,称为CentralFreeList,供各线程的ThreadCache从中获取空闲对象。线程从CentralCache中取用或回收对象,是须要加锁的。为了平摊锁操做的开销,ThreadCache通常从CentralCache中一次性取用或回收多个空闲对象。
CentralCache在TCMalloc中是一个逻辑上的概念,本质是CentralFreeList类型的数组。CentralCache简化结构以下:
(4)PageHeap
当CentralCache中的空闲对象不够用时,CentralCache会向PageHeap申请一块内存(可能来自PageHeap的缓存,也可能向系统申请新的内存),并将其拆分红一系列空闲对象,添加到对应size class的CentralFreeList中。
PageHeap内部根据内存块(span)的大小采起了两种不一样的缓存策略。128个page之内的span,每一个大小都用一个链表来缓存,超过128个page的span,存储于一个有序set(std::set)。
(5)内存回收
应用程序调用free或delete一个小对象时,仅是将其插入到ThreadCache中其size class对应的FreeList中,不须要加锁,所以速度很是快。
只有当知足必定的条件时,ThreadCache中的空闲对象才会从新放回CentralCache中,以供其它线程取用。当知足必定条件时,CentralCache中的空闲对象也会还给PageHeap,PageHeap再还给系统。
TCMalloc对于超过256KB但不超过1MB(128个page)的中对象分配采起了与小对象不一样的分配策略。TCMalloc会将应用程序所要申请的内存大小向上取整到整数个page(会产生1B~8KB内部碎片),而后向PageHeap申请一个指定page数量的span并返回其起始地址便可。
对于128个page之内的span,PageHeap中有128个span的链表,分别对应1~128个page的span。
假设要分配一块内存,其大小通过向上取整后对应k个page,所以须要从PageHeap取一个大小为k个page的span。分配过程以下:
(1)首先从k个page的span链表开始,到128个page的span链表,按顺序找到第一个非空链表。
(2)取出非空链表中的一个span,假设有n个page,将span拆分红两个span:一个span大小为k个page,做为分配结果返回;另外一个span大小为n – k个page,从新插入到n – k个page的span链表中。
(3)若是找不到非空链表,则将分配看作是大对象分配。
四、大内存分配
TCMalloc对于超过1MB(128个page)的大对象分配须要先将所要分配的内存大小向上取整到整数个page,假设是k个page,而后向PageHeap申请一个k个page大小的span。
大对象分配用到的span都是超过128个page的span,其缓存方式不是链表,而是一个按span大小排序的有序set(std::set),以便按大小进行搜索。
假设要分配一块超过1MB的内存,其大小通过向上取整后对应k个page(k>128),或者是要分配一块1MB之内的内存,但没法由中对象分配逻辑来知足,此时k <= 128。分配过程以下:
(1)搜索span set,找到不小于k个page的最小的span,假设span有n个page。
(2)将span拆分为两个span:一个span大小为k个page,做为结果返回;另外一个span大小为n – k个page,若是n – k > 128,则将其插入到大span的set中,不然,将其插入到对应的小span链表中。
(3)若是找不到合适的span,则使用sbrk或mmap向系统申请新的内存以生成新的span,并从新执行中对象或大对象的分配算法。
libtcmalloc_and_profiler.so
libtcmalloc_debug.so
libtcmalloc_minimal_debug.so
libtcmalloc_minimal.so
libtcmalloc.so
libtcmalloc_minimal版本不包含heap profiler和heap checker。
经过-ltcmalloc或-ltcmalloc_minimal将TCMalloc连接到应用程序。
经过LD_PRELOAD预载入TCMalloc库能够不用从新编译应用程序便可使用TCMalloc。LD_PRELOAD="/usr/lib/libtcmalloc.so"
在编译选项的最后加入/usr/local/lib/libtcmalloc_minimal.a连接静态库。
TCMalloc在libc_override.h中实现了覆盖机制,在使用指定-ltcmalloc连接后,应用程序对malloc、free、new、delete等调用就从默认glibc中的函数调用变为TCMalloc库中相应的函数调用。
(1)仅使用GLibc库
在glibc中,内存分配相关的函数都是弱符号(weak symbol),所以TCMalloc只须要定义本身的函数将其覆盖便可。
libc_override_redefine.h中定义以下:
void* operator new(size_t size) { return TCMallocInternalNew(size); } void operator delete(void* p) noexcept { TCMallocInternalDelete(p); } void* operator new[](size_t size) { return TCMallocInternalNewArray(size); } void operator delete[](void* p) noexcept { TCMallocInternalDeleteArray(p); } void* operator new(size_t size, const std::nothrow_t& nt) noexcept { return TCMallocInternalNewNothrow(size, nt); } void* operator new[](size_t size, const std::nothrow_t& nt) noexcept { return TCMallocInternalNewArrayNothrow(size, nt); } void operator delete(void* ptr, const std::nothrow_t& nt) noexcept { return TCMallocInternalDeleteNothrow(ptr, nt); } void operator delete[](void* ptr, const std::nothrow_t& nt) noexcept { return TCMallocInternalDeleteArrayNothrow(ptr, nt); } extern "C" { void* malloc(size_t s) noexcept { return TCMallocInternalMalloc(s); } void free(void* p) noexcept { TCMallocInternalFree(p); } void sdallocx(void* p, size_t s, int flags) { TCMallocInternalSdallocx(p, s, flags); } void* realloc(void* p, size_t s) noexcept { return TCMallocInternalRealloc(p, s); } void* calloc(size_t n, size_t s) noexcept { return TCMallocInternalCalloc(n, s); } void cfree(void* p) noexcept { TCMallocInternalCfree(p); } void* memalign(size_t a, size_t s) noexcept { return TCMallocInternalMemalign(a, s); } void* valloc(size_t s) noexcept { return TCMallocInternalValloc(s); } void* pvalloc(size_t s) noexcept { return TCMallocInternalPvalloc(s); } int posix_memalign(void** r, size_t a, size_t s) noexcept { return TCMallocInternalPosixMemalign(r, a, s); } void malloc_stats(void) noexcept { TCMallocInternalMallocStats(); } int mallopt(int cmd, int v) noexcept { return TCMallocInternalMallOpt(cmd, v); } #ifdef HAVE_STRUCT_MALLINFO struct mallinfo mallinfo(void) noexcept { return TCMallocInternalMallocInfo(); } #endif size_t malloc_size(void* p) noexcept { return TCMallocInternalMallocSize(p); } size_t malloc_usable_size(void* p) noexcept { return TCMallocInternalMallocSize(p); } } // extern "C"
(2)使用GCC编译器编译
若是使用了GCC编译器,则使用其支持的函数属性:alias。
libc_override_gcc_and_weak.h:
#define TCMALLOC_ALIAS(tc_fn) \ __attribute__((alias(#tc_fn), visibility("default"))) void* operator new(size_t size) noexcept(false) TCMALLOC_ALIAS(TCMallocInternalNew); void operator delete(void* p) noexcept TCMALLOC_ALIAS(TCMallocInternalDelete); void operator delete(void* p, size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteSized); void* operator new[](size_t size) noexcept(false) TCMALLOC_ALIAS(TCMallocInternalNewArray); void operator delete[](void* p) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteArray); void operator delete[](void* p, size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteArraySized); void* operator new(size_t size, const std::nothrow_t& nt) noexcept TCMALLOC_ALIAS(TCMallocInternalNewNothrow); void* operator new[](size_t size, const std::nothrow_t& nt) noexcept TCMALLOC_ALIAS(TCMallocInternalNewArrayNothrow); void operator delete(void* p, const std::nothrow_t& nt) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteNothrow); void operator delete[](void* p, const std::nothrow_t& nt) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteArrayNothrow); void* operator new(size_t size, std::align_val_t alignment) noexcept(false) TCMALLOC_ALIAS(TCMallocInternalNewAligned); void* operator new(size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept TCMALLOC_ALIAS(TCMallocInternalNewAligned_nothrow); void operator delete(void* p, std::align_val_t alignment) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteAligned); void operator delete(void* p, std::align_val_t alignment, const std::nothrow_t&) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteAligned_nothrow); void operator delete(void* p, size_t size, std::align_val_t alignment) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteSizedAligned); void* operator new[](size_t size, std::align_val_t alignment) noexcept(false) TCMALLOC_ALIAS(TCMallocInternalNewArrayAligned); void* operator new[](size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept TCMALLOC_ALIAS(TCMallocInternalNewArrayAligned_nothrow); void operator delete[](void* p, std::align_val_t alignment) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteArrayAligned); void operator delete[](void* p, std::align_val_t alignment, const std::nothrow_t&) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteArrayAligned_nothrow); void operator delete[](void* p, size_t size, std::align_val_t alignemnt) noexcept TCMALLOC_ALIAS(TCMallocInternalDeleteArraySizedAligned); extern "C" { void* malloc(size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalMalloc); void free(void* ptr) noexcept TCMALLOC_ALIAS(TCMallocInternalFree); void sdallocx(void* ptr, size_t size, int flags) noexcept TCMALLOC_ALIAS(TCMallocInternalSdallocx); void* realloc(void* ptr, size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalRealloc); void* calloc(size_t n, size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalCalloc); void cfree(void* ptr) noexcept TCMALLOC_ALIAS(TCMallocInternalCfree); void* memalign(size_t align, size_t s) noexcept TCMALLOC_ALIAS(TCMallocInternalMemalign); void* aligned_alloc(size_t align, size_t s) noexcept TCMALLOC_ALIAS(TCMallocInternalAlignedAlloc); void* valloc(size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalValloc); void* pvalloc(size_t size) noexcept TCMALLOC_ALIAS(TCMallocInternalPvalloc); int posix_memalign(void** r, size_t a, size_t s) noexcept TCMALLOC_ALIAS(TCMallocInternalPosixMemalign); void malloc_stats(void) noexcept TCMALLOC_ALIAS(TCMallocInternalMallocStats); int mallopt(int cmd, int value) noexcept TCMALLOC_ALIAS(TCMallocInternalMallOpt); struct mallinfo mallinfo(void) noexcept TCMALLOC_ALIAS(TCMallocInternalMallocInfo); size_t malloc_size(void* p) noexcept TCMALLOC_ALIAS(TCMallocInternalMallocSize); size_t malloc_usable_size(void* p) noexcept TCMALLOC_ALIAS(TCMallocInternalMallocSize); } // extern "C"
将宏展开,__attribute__ ((alias ("tc_malloc"), default))
代表tc_malloc是malloc的别名。
默认状况下,TCMaloc会将长时间未用的内存交还系统。tcmalloc_release_rate标识用于控制交回频率,能够在运行时强制调用ReleaseFreeMemory回收未使用内存。MallocExtension::instance()->ReleaseFreeMemory();
经过 SetMemoryReleaseRate来设置tcmalloc_release_rate。若是设置为0,表明永远不交回;数字越大表明交回的频率越大,值在0-10之间,能够经过设置 TCMALLOC_RELEASE_RATE环境变量来设置。
GetMemoryReleaseRate能够查看当前释放的几率值。
TCMALLOC_SAMPLE_PARAMETER:采样时间间隔,默认值为0。
TCMALLOC_RELEASE_RATE:释放未使用内存的频率,默认值为1.0。
TCMALLOC_LARGE_ALLOC_REPORT_THRESHOLD:内存最大分配阈值,默认值为1073741824(1GB)。
TCMALLOC_MAX_TOTAL_THREAD_CACHE_BYTES:分配给线程缓冲的最大内存上限,默认值为16777216(16MB)。
malloc.cpp:
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <time.h> #define MAX_OBJECT_NUMBER (1024) #define MAX_MEMORY_SIZE (1024*100) struct BufferUnit{ int size; char* data; }; struct BufferUnit buffer_units[MAX_OBJECT_NUMBER]; void MallocBuffer(int buffer_size) { for(int i=0; i<MAX_OBJECT_NUMBER; ++i) { if (NULL != buffer_units[i].data) continue; buffer_units[i].data = (char*)malloc(buffer_size); if (NULL == buffer_units[i].data) continue; memset(buffer_units[i].data, 0x01, buffer_size); buffer_units[i].size = buffer_size; } } void FreeHalfBuffer(bool left_half_flag) { int half_index = MAX_OBJECT_NUMBER / 2; int min_index = 0; int max_index = MAX_OBJECT_NUMBER-1; if (left_half_flag) max_index = half_index; else min_index = half_index; for(int i=min_index; i<=max_index; ++i) { if (NULL == buffer_units[i].data) continue; free(buffer_units[i].data); buffer_units[i].data = NULL; buffer_units[i].size = 0; } } int main() { memset(&buffer_units, 0x00, sizeof(buffer_units)); int decrease_buffer_size = MAX_MEMORY_SIZE; bool left_half_flag = false; time_t start_time = time(0); while(1) { MallocBuffer(decrease_buffer_size); FreeHalfBuffer(left_half_flag); left_half_flag = !left_half_flag; --decrease_buffer_size; if (0 == decrease_buffer_size) break; } FreeHalfBuffer(left_half_flag); time_t end_time = time(0); long elapsed_time = difftime(end_time, start_time); printf("Used %ld seconds. \n", elapsed_time); return 1; }
使用TCMalloc编译连接:g++ malloc.cpp -o test -ltcmalloc
执行test,耗时334秒。
使用默认GLibc编译连接:g++ malloc.cpp -o test
执行test,耗时744秒。