dlmalloc解析连载三

上一篇讨论了dlmalloc大小在256字节以下的chunk块进行的组织管理,本篇我们再来看看对于大小在256字节以上的chunk块,dlmalloc是如何管理的。

对于大小在256字节以上的chunk块,dlmalloc也采用了所谓的分箱机制,不过由于大于256的数目有很多,因此这里的分箱不能够像对于0256这个有限区间的分箱来得简单。具体来说如下表:

字节范围

范围大小

箱号

[256, 384)

128

0

[384, 512)

128

1

[512, 768)

256

2

[768, 1024)

256

3

[1024, 1536)

512

4

[1536, 2048)

512

5

[2048, 3072)

1024

6

[3072, 4096)

1024

7

[4096, 6144)

2048

8

[6144, 8192)

2048

9

[8192, 12288)

4096

10

[12288, 16384)

4096

11

[16384, 24576)

8192

12

[24576, 32768)

8192

13

[32768, 49152)

16384

14

[49152, 65536)

16384

15

[65536, 98304)

32768

16

[98304, 131072)

32768

17

[131072, 196608)

65536

18

[196608, 262144)

65536

19

[262144, 393216)

131072

20

[393216, 524288)

131072

21

[524288, 786432)

262144

22

[786432, 1048576)

262144

23

[1048576, 1572864)

524288

24

[1572864, 2097152)

524288

25

[2097152, 3145728)

1048576

26

[4194304, 4194304)

1048576

27

[4194304, 6291456)

2097152

28

[6291456, 8388608)

2097152

29

[8388608, 12582912)

4194304

30

[12582912, 理论上无穷大)

理论上无穷大

31

 

这个表格里的数字是我先用程序打印出来然后再拷贝过来的,先简单解释一下,第一列“字节范围”表示大小在该范围内chunk块被分配到改行对应的第三列“箱号”所指定的箱子内。第二列表示第一列“字节范围”的范围大小,各位可以看到它们很有规律,在后面我们会讲到这种规律性的作用,因此这里也就先给出来。另外,这种规律性也就是这样分箱的分法,相比上一篇中的那种直接按8162432…这种确定值的分箱方法相对较为复杂,这里是将一个区间内的值分到一个箱子内,正因如此,对于箱内chunk块的管理也就不能再简单的使用双向链表而是使用树(实际上在具体实现上为Trie树,不过和课本上的那种字典Trie树不一样,Doug Lea给出的注释称之为“bitwise digital trees (aka tries)”,要怎么去把它讲清楚还真不简单啊,试着按照从抽象概念到实现细节的方式来说明吧,另外姑且称这种树为dltree树)结构,当然这种树不是随意的,它具有它自身的最简单规则:①任何节点的左子树上所有节点值均小于它的右子树上所有节点值。②任何节点值和它的左(右)子树上所有节点值不存在确定排序关系。这是直白的描述,如果用更严谨的表述则为如下:

dltree树或者是一颗空树;或者是具有下列性质的二叉树:

1)若左子树和右子树都不空,则左子树上所有结点的值均小于右子树上所有结点的值;

2)左、右子树也分别为dltree树;

 

       每一个箱子里的chunk块都被以dltree树结构组织起来,分了32个箱号,因此dlmalloc具有32dltree树,记录该32dltree树根节点的指针变量也定义在结构体malloc_state,如下:

tbinptr    treebins[NTREEBINS];

#define NTREEBINS (32U)

typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */

其中NTREEBINS为常量宏,类型tbinptrmalloc_tree_chunk结构体指针,数组的32个指针元素指向32个分箱内各个dltree树的根节点,因此通过结构体malloc_state类型变量很方便的找到各种chunk块大小范围的树结构。

 

        

 

         下面讨论具体一棵dltree树的组织情况(就以0号箱管理的树为例),根据dltree树中左子树小于右子树的性质,字节[256, 384)范围被按如下规则划分给0号箱管理的dltree树组织:

         根的左子树T1管理[256, 320),右子树T2管理[320, 384),即各管理64字节范围。

       T1的左子树T3管理[256, 288),树T1的右子树T4管理[288, 320),即各管理32字节范围。树T2类似。

       T3的左子树T7管理[256, 272),树T3的右子树T8管理[272, 288),即各管理16字节范围。其它树类似。

       ……

      

 

       通过这种分法,任一号箱的字节范围被对应在一颗树上,在查找某一大小的空闲chunk时则按照这种规律来进行“快速”搜索,比如应用程序malloc( 278 ),则由于278[256, 320)范围内,因此先进入树T1,接着由于278[256, 288)范围内,因此由进入T3,接着进入T8,……。

       之所以说这种搜索是“快速”的,因为这里的范围划为很巧妙,我们来看一下各字节范围用二进制表示的情况:

       根节点T的左子树T1 [256, 320)为:

       [1 0000 0000  1 00xx xxxx]

       而根节点T的右子树T2 [320, 384)为:

       [1 01xx xxxx  1 01xx xxxx]

       其中的x表示为1或者0,可以看到T1T2的管理范围很好区分,即通过判断第6bit位是否为1即可。为1表示在右子树T2范围内,为0表示在左子树T1范围内。

 

       再来看看树T1的左子树T3和右子树T4情况:

       T3管理[256, 288)为:

       [1 0000 0000  1 000x xxxx]

       T4管理[288, 320)为:

       [1 0010 0000  1 001x xxxx]

       可以看到T3T4的管理范围也很好区分,即通过判断第5bit位是否为1即可。为1表示在右子树T4范围内,为0表示在左子树T3范围内。

 

       其它的类似……。因此,我们在查找某字节在哪个范围内的树上只需要顺序的比较各bit位就可以了,对比Trie树,我们可以认为dltree是关键码只有01Trie

 

       还有其他细节,比如当应用程序申请某一字节的内存空间,而该字节所属范围tree不存在时则只有在更接近该范围的tree内申请节点,这些都是具体实现,后面会具体讲到吧。

 

转载请保留本博客地址连接[http://lenky0401.cublog.cn],谢谢。

你可能感兴趣的:(struct,tree)