TCMalloc的使用与源码剖析之二---------TCMalloc内存分配与管理简述

来源:互联网 发布:stl源码解析 编辑:程序博客网 时间:2024/05/17 19:19

        TCMalloc给每个线程分配了一个线程局部缓存,小对象的分配是直接由线程局部缓存来完成的,这样就避免了多线程程序中的锁竞争情况。当线程局部缓存中的内存不够时,会将对象从中央数据结构移动到线程局部缓存中,同时定期的用垃圾收集器把内存从线程局部缓存迁移回中央数据结构中。

         TCMalloc将尺寸小于等于256 * 1024字节的对象(对象)和大对象区分开来。大对象直接使用页级分配器从中央页堆直接分配。即,一个大对象总是页对齐的并占据了整数个数的页。

1.小对象的分配

        每个小对象的大小都会被映射到与之接近的可分配的class中的一个。例如,所有大小在8331024字节之间的小对象时,都会归整到1024字节。60个可分配的尺寸类别这样隔开:较小的尺寸相差8字节,较大的尺寸相差16字节,再大一点的尺寸差32字节,如此等等。最大的间隔是控制的,这样刚超过上一个级别被分配到下一个级别就不会有太多的内存被浪费。

一个线程缓存包含了由各个尺寸内存的对象组成的单链表,如图所示:

        

        当分配一个小对象时:(1)我们将其大小映射到对应的尺寸中。2)查找当前线程的线程缓存中相应的尺寸的内存链表。3)如果当前尺寸内存链表非空,那么从链表中移除的第一个对象并返回它。当我们按照这种方式分配时,TCMalloc不需要任何锁。这就可以极大提高分配的速度,因为锁/解锁操作在一个2.8GHzXeon上大约需要100纳秒的时间。

如果当前尺寸内存链表为空:(1)从Central Cache中取得一系列这种尺寸的对象(CentralCache是被所有线程共享的)。2)将他们放入该线程线程的缓冲区3)返回一个新获取的对象给应用程序。

如果CentralCache也为空:(1)我们从中央页堆中分配一系列页面。(2)将他们分割成该尺寸的一系列对象。(3)将新分配的对象放入CentralCache的链表上 (4) 像前面一样,将部分对象移入线程局部的链表中。

如果中央页堆也为空,那么就从系统中分配一系列的页面(使用sbrkmmap或者通过在/dev/mem中进行映射),把页面给中央页堆,然后继续上面的操作

 

2.大对象的分配

一个大对象的尺寸会被中央页堆直接处理,被圆整到一个页面尺寸(4K)。中央页堆是由空闲内存列表组成的数组。对于i < 256而言,数组的第k个元素是一个由每个单元是由k个页面组成的空闲内存链表。第256个条目则是一个包含了长度>= 256个页面的空闲内存链表:

  

k个页面的一次分配通过在第k个空闲内存链表中查找来完成。如果该空闲内存链表为空,那么我们则在下一个空闲内存链表中查找,如此继续。最终,如果必要的话,我们将在最后空闲内存链表中查找。如果这个动作也失败了,我们将向系统获取内存(使用sbrkmmap或者通过在/dev/mem中进行映射)

如果k个页面的分配是由连续的> k个页面的空闲内存链表完成的,剩下的连续页面将被重新插回到与之页面大小接近的空闲内存链表中去。

0 0