您的位置:首页 > 其它

TCMalloc的使用与源码剖析之十--------TCMalloc与APR,ptmalloc的分析比较

2016-10-22 11:22 609 查看
一. tcmalloc与APR,ptmalloc的不同点

(1)

1. tcmalloc与APR初始化时都不会预先分配内存。但是tcmalloc申请一个小对象后(最开始时的申请,此时threadCache,CentralCache等结构中还没内存),便会向系统申请几个页面的内存,中央页堆,CentralCache,threadCache会分别标记属于他们的内存。然后再从threadCache中分配一个obj给申请者。

2. 而APR不一样,申请者申请内存(最开始时的申请), 新分配的内存并不挂接到内存分配器链表中,而是在调用allocator_free进行内存释放的时候,内存才可能挂到内存分配器链表上。新分配的内存在内存池节点的active链表中。

这也即是APR的一大缺点:apr_pool的一个大缺点就是从池中申请的内存不能归还给内存池,只能等pool销毁的时候才能归还。为了弥补这个缺点,apr_pool的实际使用中,可以申请拥有不同生命周期的内存池。

3. Ptmalloc:在使用malloc之前,heap大小为0.若请求空间小于mmap分配阈值,主分配区会调用sbrk()增加一块大小为(128kb+chunk_size)align4KB的空间作为heap。非主分配区会调用一块大小为HEAP_MAX_SIZE(32位系统上默认为1M,64位系统上默认为64M)的空间作为sub_heap(3.2.3.4小节),这就是ptmalloc维护的分配空间。

当用户释放了heap中的chunk时,ptmalloc又会使用fastbins和bins来组织空闲chunk,以备下一次分配。

所以三者对内存的维护处理各不相同,初始化时三者都不会预分配空间。但一旦有了malloc,tcmalloc与ptmalloc便会预先分配一块大内存加入内存池(应该可以称为内存池吧),tcmalloc把内存分到各级,但是ptmalloc只是放在heap中。

(2)tcmalloc应该是只有一个内存池的概念,而APR则是多内存池概念。

二.各内存池的优缺点

Ptmalloc缺点:

1. 多线程由于锁冲突,所以慢

2. 容易造成内存暴增:因为ptmalloc的内存收缩是从topchunk开始,如果与topchunk相邻的那个chunk没有被释放,topchunk以下的空闲内存都无法返回给系统,即是这些空闲内存有几十个G也不行。(ptmalloc文档第4节)

3. 容易造成内存碎片(ptmalloc文档第4节第5点),ptmalloc就不会存在这种大块内存碎片的问题,由于其内存管理机制。不过ptmalloc也会引起小的内存碎片,比如我申请的是13字节,对应的size是15字节,那么便会有2个自己的内存碎片。不过

APR缺点:

APR从系统申请来的内存先是放在内存池节点的active链表中链起来,并不会加入内存分配器的free链表数组。所以当内存中一直是在malloc,但是却没有free时,active链表链接了大量内存,而free链表数组一直没值,这样容易把系统内存耗尽

APR优点:可以建立子内存池,这样建立不同周期的内存池。 比如连接内存池与请求内存池

看这些个分配器的分配机制,可见这些内存管理机制都是针对小内存分配和管理。对大块内存还是直接用了系统调用。所以在程序中应该尽量避免大内存的malloc/new、free/delete操作。另外这个分配器的最小粒度都是以8字节为单位的,所以频繁分配小内存,像int啊bool啊什么的,仍然会浪费空间。经过测试无论是对bool、int、short进行new的时候,实际消耗的内存在ptmalloc和tcmalloc下64位系统地址间距都是32个字节。大量new测试的时候,ptmalloc平均每次new消耗32字节,tcmalloc消耗8字节(我想说ptmalloc弱爆啦,而且tcmalloc)。所以大量使用这些数据的时候不妨用数组自己维护一个内存池,可以减少很多的内存浪费。(原来STL的map和set一个节点要消耗近80个字节有这么多浪费在这里了啊)

而多线程下对于比较大的数据结构,为了减少分配时的锁争用,最好是自己维护内存池。单线程的话无所谓了,呵呵。不过自己维护内存池是增加代码复杂度,减少 内存管理复杂度。但是我觉得,255个分页以下(1MB)的内存话,tcmalloc的分配和管理机制已经相当nice,没太大必要自己另写一个。

另外,Windows下内存分配方式不知道,不同类型(int、short和bool)连续new的地址似乎是隔开的,可能是内部实现的粒度更小,不同size的class更多。测试10M次new的时候,debug模式下明显卡顿了一下,平均每次new的内存消耗是52字节(32位)和72字节(64位)[header更复杂?]。但是Release模式下很快,并且平均每次new的内存消耗是20字节(32位)和24字节(64位)。可以猜测VC的malloc的debug模式还含有挺大的debug信息。是不是可以得出他的header里,Release版本只有1个指针,Debug里有5个指针呢?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐