内存堆块结构
malloc 申请的内存为 chunk 。这块内存在 ptmalloc 内部用 malloc_chunk 结构体来表示
结构定义如下
1 | struct malloc_chunk { |
- prev_size仅在前一个堆块(较低地址)是
free
状态才生效。 - size指的是本chunk的大小即为图中
chunk
到nextchunk
的大小 - fd是指向下一个(非物理相邻)被
free
的 chunk - bk 指向上一个(非物理相邻)被
free
的 chunk - fd_nextsize 指向前一个与当前 chunk 大小不同的第一个空闲块
- bk_nextsize 指向后一个与当前 chunk 大小不同的第一个空闲块
简单来讲chunk分为正在使用的chunk:
allocated chunk
和被free的chunk:free chunk
正在使用的chunk如图所示,数据从fd开始写,可能写到下一个chunk的prev_use位
可以说除了size,其他字段都用来写数据,在chunk被free才会发挥各个字段的作用
各部分详解
prev_size只有当该chunk的物理相邻的前一地址chunk是空闲的话,该字段在本chunk中才有用,用来记录前一个chunk 的大小 (包括chunk头)。只有
chunk 被free
空闲的时候才使用,如果前一个chunk未被free,前一个chunk可以覆写到presize位,正如图中所示,chunk可以写内容(user data)到下一个堆块的pre_size
这就是 chunk 中的空间复用这样看起来好像size位才是chunk的开始。?
但是chunk块的地址从这里开始
size记录当前chunk的大小,大小一般是 2 * SIZE_SZ 的最小整数倍。
若
malloc(n)
则size
=(n+SIZE_SZ)再补齐,我是看做
data
部分大小加上size
位的大小再补齐SIZE_SZ= 4(32位系统)或8(64位系统)
另外size后三位有特殊用途,所以size的真正大小要将后三位取0
NON_MAIN_ARENA,记录当前 chunk 是否不属于主线程,1 表示不属于,0 表示属于。
IS_MAPPED,记录当前 chunk 是否是由 mmap 分配的。
PREV_INUSE,记录前一个 chunk 块是否被分配。一般来说,堆中第一个被分配的内存块的 size 字段的 P 位都会被设置为 1,以便于防止访问前面的非法内存。当一个 chunk 的 size 的 P 位为 0 时,我们能通过 prev_size 字段来获取上一个 chunk 的大小以及地址。这也方便进行空闲 chunk 之间的合并。
fd,bk
malloc成功时返回的地址就是fd的地址
chunk 处于分配状态时,从 fd 字段开始是用户的数据,
chunk 被free
后才发挥作用- fd 指向下一个(非物理相邻)空闲的 chunk
- bk 指向上一个(非物理相邻)空闲的 chunk
fd_nextsize, bk_nextsize
chunk 被free
的时候才使用,用于large chunk
。- fd_nextsize 指向前一个与当前 chunk 大小不同的第一个空闲块,不包含 bin 的头指针。
- bk_nextsize 指向后一个与当前 chunk 大小不同的第一个空闲块,不包含 bin 的头指针。