glibc中的bins链表详解
glibc
中的bins
链表详解
[toc]
不知道是否有师傅和我一样,有时候会迷失在glibc
的链表中,傻傻分不清楚fd
和bk
指向的是什么,也会忘记chunk
的释放和分配顺序。因此就有了这篇文章,以一系列小实验来记录下各个链表的fd
、bk
指针的作用,以及各个链表的分配顺序。
fastbin
通过以下代码在glibc2.23
进行测试:
1 |
|
其输出为:
1 |
|
这证明:
fastbin
是LIFO
(Last in, Fist out
),即最后释放的chunk
会最先被申请回去。这种分配方式满足操作系统上的时间局部性。fastbin
中只存在fd
指针,不存在bk
指针,后释放的chunk
的fd
指针指向先释放的chunk
。- 从链表头添加,从链表头取出。
即:
unsortedbin
通过以下代码在glibc2.23
进行测试:
1 |
|
其输出为:
1 |
|
这说明:
unsortedbin
是遵循FIFO
(First in, First out
)的,即先释放的会先被申请出去。unsortedbin
的fd
指针指向比他先释放的chunk
,而bk
指针指向比它后释放的chunk
。fd
和bk
指针都会指向main_arena
,因此最先释放的chunk
的fd
指针将会指向main_arena
,而最后释放的chunk
的bk
指针会指向main_arena
。- 从链表头插入,从链表尾取出
即:
smallbin
通过以下代码在glibc2.23
进行测试:
1 |
|
其输出为:
1 |
|
这说明:
- 其和
unsortedbin
的管理机制基本一样,同样为FIFO
,只是unsortedbin
只有一条链,而smallbin
根据大小不同,有很多链。 smallbin
的fd
指针指向比他先释放的chunk
,而bk
指针指向比它后释放的chunk
。fd
和bk
指针都会指向main_arena
,因此最先释放的chunk
的fd
指针将会指向main_arena
,而最后释放的chunk
的bk
指针会指向main_arena
。- 从链表头插入,从链表尾取出
即:
largebin
largebin
的链表结构比较复杂,若仍然使用代码的形式给读者展示,比较晦涩。这部分内容可以查看Rolan师傅的文章进行参考。这里放一张以前画的largebin
的结构图。
其中:
每一个
largebin
中存放的chunk
大小是不相同的,一共有63
个largebin
。在这63
个largebin
中,前32
个largebin
的最大chunk
和最小的chunk
之差为64bytes(0x40)
。例如第一个largebin
的大小为512bytes-568bytes
(32
位),而第二个largebin
的大小就为576bytes-632bytes
。每一个
largebin
中的chunk
按照大小顺序从大到小排序。若大小相同,则会按照释放顺序排序:最先释放的
chunk
拥有fd_nextsize
和bk_nextsize
指针,之后的chunk
的这两个指针的值都为0
。若将这个chunk
称为小堆头,那么后面释放的chunk
都会被插入到小堆头的后面。因此,对于同一个大小的large chunk
,最先释放的在最上面,除此之外越先释放在越后面。fd_nextsize
和bk_nextsize
是指向当前bin
的下一个大小的chunk
。fd_nextsize
指向比自己小的,而bk_nextsize
指向比自己大的。
tcache
通过以下代码在glibc2.27
下完成测试:
1 |
|
其结果如下:
(根据glibc
版本的不同,其bk
指针有差异,指示的是其安全规则)
1 |
|
从上面可以看到:
tcache
的管理机制和fastbin
的管理机制很像,区别在于tcache
还包括smallbin
大小,且其bk
指针用于安全校验。tcache
是LIFO
(Last in, Fist out
),即最后释放的chunk
会最先被申请回去。这种分配方式满足操作系统上的时间局部性。tcache
同样也是后释放的chunk
的fd
指针指向先释放的chunk
。- 从链表头添加,从链表头取出。
即:(是的,我只需要更改fastbin
为tcache
即可。)