作者@走位,阿里聚安全
0 前言回顾
在上一篇文章中,详细介绍了堆内存管理中涉及到的基本概念以及相互关系,同时也着重介绍了堆中chunk分配和释放策略中使用到的隐式链表技术。通过前面的介绍,我们知道使用隐式链表来管理内存chunk总会涉及到内存的遍历,效率极低。对此glibc malloc引入了显示链表技术来提高堆内存分配和释放的效率。
所谓的显示链表就是我们在数据结构中常用的链表,而链表本质上就是将一些属性相同的“结点”串联起来,方便管理。在glibc malloc中这些链表统称为bin,链表中的“结点”就是各个chunk,结点的共同属性就是:1)均为free chunk;2)同一个链表中各个chunk的大小相等(有一个特例,详情见后文)。
1 bin介绍
如前文所述,bin是一种记录free chunk的链表数据结构。系统针对不同大小的free chunk,将bin分为了4类:1) Fast bin; 2) Unsorted bin; 3) Small bin; 4) Large bin。
在glibc中用于记录bin的数据结构有两种,分别如下所示:
fastbinsY: 这是一个数组,用于记录所有的fast bins;
bins: 这也是一个数组,用于记录除fast bins之外的所有bins。事实上,一共有126个bins,分别是:
bin 1 为unsorted bin;
bin 2 到63为small bin;
bin 64到126为large bin。
其中具体数据结构定义如下:
struct malloc_state { …… /* Fastbins */ mfastbinptr fastbinsY[NFASTBINS]; …… /* Normal bins packed as described above */ mchunkptr bins[NBINS * 2 - 2]; // #define NBINS 128 …… }; 这里mfastbinptr的定义:typedef struct malloc_chunk *mfastbinptr; mchunkptr的定义:typedef struct malloc_chunk* mchunkptr; |
画图更直观:
图1-1 bins分类
那么处于bins中个各个free chunk是如何链接在一起的呢?回顾malloc_chunk的数据结构:
struct malloc_chunk { /* #define INTERNAL_SIZE_T size_t */ INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* 这两个指针只在free chunk中存在*/ struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */ struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */ struct malloc_chunk* bk_nextsize; }; |
其中的fd和bk指针就是指向当前chunk所属的链表中forward或者backward chunk。
2 Fast bin
既然有fast bin,那就肯定有fast chunk——chunk size为16到80字节的chunk就叫做fast chunk。为了便于后文描述,这里对