首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 操作系统 >

Glibc内存储器管理-ptmalloc2源代码分析(十四)

2012-08-09 
Glibc内存管理--ptmalloc2源代码分析(十四).2.2? Large bins在SIZE_SZ为4B的平台上,大于等于512B的空闲chu

Glibc内存管理--ptmalloc2源代码分析(十四)

.2.2? Large bins

在SIZE_SZ为4B的平台上,大于等于512B的空闲chunk,或者,在SIZE_SZ为8B的平台上,大小大于等于1024B的空闲chunk,由sorted bins管理。Large bins一共包括63个bin,每个bin中的chunk大小不是一个固定公差的等差数列,而是分成6组bin,每组bin是一个固定公差的等差数列,每组的bin数量依次为32、16、8、4、2、1,公差依次为64B、512B、4096B、32768B、262144B等。

以SIZE_SZ为4B的平台为例,第一个largebin的起始chunk大小为512B,共32个bin,公差为64B,等差数列满足如下关系:

Chunk_size=512 +64 * index

第二个large bin的起始chunk大小为第一组bin的结束chunk大小,满足如下关系:

Chunk_size=512 +64 * 32 + 512 * index

同理,我们可计算出每个bin的起始chunk大小和结束chunk大小。这些bin都是很有规律的,其实smallbins也是满足类似规律,small bins可以看着是公差为8的等差数列,一共有64个bin(第0和1bin不存在),所以我们可以将small bins和large bins存放在同一个包含128个chunk的数组上,数组的前一部分位small bins,后一部分为large bins,每个bin的index为chunk数组的下标,于是,我们可以根据数组下标计算出该bin的chunk大小(small bins)或是chunk大小范围(large bins),也可以根据需要分配内存块大小计算出所需chunk所属bin的index,ptmalloc使用了一组宏巧妙的实现了这种计算。

开始(字节)

结束(字节)

0

7

不存在

8

15

不存在

16

23

2

24

31

3

32

39

4

40

47

5

48

55

6

56

63

7

64

71

8

72

79

9

80

87

10

88

95

11

96

103

12

104

111

13

112

119

14

120

127

15

128

135

16

136

143

17

144

151

18

152

159

19

160

167

20

168

175

21

176

183

22

184

191

23

192

199

24

200

207

25

208

215

26

216

223

27

224

231

28

232

239

29

240

247

30

248

255

31

256

263

32

?

/* addressing -- note that bin_at(0) does not exist */#define bin_at(m, i) \ (mbinptr) (((char *) &((m)->bins[((i) - 1) * 2])) \ - offsetof (struct malloc_chunk, fd))/* analog of ++bin */#define next_bin(b) ((mbinptr)((char*)(b) + (sizeof(mchunkptr)<<1)))/* Reminders about list directionality within bins */#define first(b) ((b)->fd)#define last(b) ((b)->bk)/* Take a chunk off a bin list */#define unlink(P, BK, FD) { \ FD = P->fd; \ BK = P->bk; \ if (__builtin_expect (FD->bk != P || BK->fd != P, 0)) \ malloc_printerr (check_action, "corrupted double-linked list", P); \ else { \ FD->bk = BK; \ BK->fd = FD; \ if (!in_smallbin_range (P->size) \ && __builtin_expect (P->fd_nextsize != NULL, 0)) { \ assert (P->fd_nextsize->bk_nextsize == P); \ assert (P->bk_nextsize->fd_nextsize == P); \ if (FD->fd_nextsize == NULL) { \ if (P->fd_nextsize == P) \ FD->fd_nextsize = FD->bk_nextsize = FD; \ else { \ FD->fd_nextsize = P->fd_nextsize; \ FD->bk_nextsize = P->bk_nextsize; \ P->fd_nextsize->bk_nextsize = FD; \ P->bk_nextsize->fd_nextsize = FD; \ } \ } else { \ P->fd_nextsize->bk_nextsize = P->bk_nextsize; \ P->bk_nextsize->fd_nextsize = P->fd_nextsize; \ } \ } \ } \}

??? 宏bin_at(m, i)通过bin index获得bin的链表头,chunk中的fb和bk用于将空闲chunk链入链表中,而对于每个bin的链表头,只需要这两个域就可以了,prev_size和size对链表都来说都没有意义,浪费空间,ptmalloc为了节约这点内存空间,增大cpu高速缓存的命中率,在bins数组中只为每个bin预留了两个指针的内存空间用于存放bin的链表头的fb和bk指针。

???????? 从bin_at(m, i)的定义可以看出,bin[0]不存在,以SIZE_SZ为4B的平台为例,bin[1]的前4B存储的是指针fb,后4B存储的是指针bk,而bin_at返回的是malloc_chunk的指针,由于fb在malloc_chunk的偏移地址为offsetof(struct malloc_chunk, fd))=8,所以用fb的地址减去8就得到malloc_chunk的地址。但切记,对bin的链表头的chunk,一定不能修改prev_size和size域,这两个域是与其他bin的链表头的fb和bk内存复用的。

???? 宏next_bin(b)用于获得下一个bin的地址,根据前面的分析,我们知道只需要将当前bin的地址向后移动两个指针的长度就得到下一个bin的链表头地址。

???? 每个bin使用双向循环链表管理空闲chunk,bin的链表头的指针fb指向第一个可用的chunk,指针bk指向最后一个可用的chunk。宏first(b)用于获得bin的第一个可用chunk,宏last(b)用于获得bin的最后一个可用的chunk,这两个宏便于遍历bin,而跳过bin的链表头。

???? 宏unlink(P, BK, FD)用于将chunk从所在的空闲链表中取出来,注意large bins中的空闲chunk可能处于两个双向循环链表中,unlink时需要从两个链表中都删除。

?

热点排行