Chunk
Chunk是Ptmalloc最基本的内存单位,这块内存在 ptmalloc 内部用 malloc_chunk 结构管理chunk。当程序申请的 chunk 被 free 后,会被加入到相应的空闲管理列表中。
chunk 有使用和空闲(释放)两种状态,其内部结构不同。
chunk结构
/*
This struct declaration is misleading (but accurate and necessary).
It declares a "view" into memory allowing access to necessary
fields at known offsets from a given base. See explanation below.
*/
struct malloc_chunk {
INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if free. */
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;
};
其字段具体解释:
prev_size
- 如果本 chunk 前面一个 chunk 处于释放状态,那么 prev_size 成员才有用,此时用来记录前一个 chunk 的大小。
- 如果本 chunk 前面一个 chunk 处于使用状态,那么 prev_size 成员为 0 是没有用的;但是当前一个 chunk 申请的大小大于前一个 chunk 的大小时,那么该字段可以用来给前一个 chunk 使用这就是 chunk 的空间复用
size
- 该 chunk 的大小,大小必须是 2 SIZE_SZ 的整数倍。如果申请的内存大小不是 2 SIZE_SZ 的整数倍,会被转换满足大小的最小的 2 * SIZE_SZ 的倍数。32 位系统中,SIZE_SZ 是 4 字节;64 位系统中,SIZE_SZ 是 8 字节。
fd 、bk
- chunk 处于使用状态时,从 fd 字段开始是用户的数据,fd 和 bk都不存在。
- chunk 释放状态时,会被添加到对应的空闲管理链表中,其字段的含义如下
- fd 指向上一个 free 的 chunk 的 prev_size
- bk 指向下一个 free 的 chunk 的 prev_size
通过 fd 和 bk 可以将空闲的 chunk 块加入到相应的链表进行统一管理
fd_nextsize、bk_nextsize
- 也是只有chunk空闲的时候才使用,不过其用于较大的chunk(large chunk):
- fd_nextsize:指向前一个与当前 chunk 大小不同的第一个空闲块,不包含bin的头指针。
- bk_nextsize:指向后一个与当前 chunk 大小不同的第一个空闲块,不包含 bin 的头指针。
- 一般空闲的 large chunk 在 fd 的遍历顺序中,按照由大到小排列。便于寻找合适 chunk 。
size 低3位
Chunk的对齐:32位 SIZE_SZ 为8字节;64位 SIZE_SZ 为16字节
Chunk的最小尺寸:32位为16字节;64位为24/32字节
8字节对齐就导致了size的低3位固定位0,然后为了充分利用内存空间,这低三位的储存了其他信息:
分别是 PREV_INUSE;IS_MMAPPED;NON_MAIN_ARENA
-
NON_MAIN_ARENA: 记录chunk是否属于不主线程,若为1则不属于,0则属于。
-
IS_MMAPPED: 1 表示使用mmap映射区域,0为使用heap区域。
-
PREV_INUSE: 为1时表示上一个chunk在使用中,0表示上一个chunk已经释放
堆管理器可以通过这些信息找到前一个被释放的chunk的位置。
Chunk有3种形式:
· Allocated chunk
· Free chunk
· Top chunk
· Last remainder chunk
常说的chunk一般也就按使用情况分为
allocated chunk:当前chunk是被应用层用户所使用的。
free chunk:当前chunk是空闲的,没有被应用层用户所使用。
下面部分需要先了解bin机制
Top Chunk:
- 概念:当一个chunk处于一个arena的最顶部(即最高内存地址处)的时候,就称之为 top chunk 即初始化后从未分配的 chunk 。
- 作用:该chunk并不属于任何bin,而是在系统当前的所有free chunk(无论那种bin)都无法满足用户请求的内存大小的时候,将此chunk 分配给用户使用。
- 分配的规则:如果top chunk的大小比用户请求的大小要大的话,就将该top chunk分作两部分:(1)用户请求的chunk;(2)剩余的部分成为新的top chunk。否则,就需要扩展heap或分配新的heap了——在main arena中通过sbrk扩展heap,而在thread arena中通过mmap分配新的heap。
Last Remainder Chunk:
-
它是怎么产生的:当用户请求的是一个small chunk,且该请求无法被small bin、unsorted bin满足的时候,就通过binmaps遍历bin查找最合适的chunk,如果该chunk有剩余部分的话,就将该剩余部分变成一个新的chunk加入到unsorted bin中,另外,再将该新的chunk变成新的last remainder chunk。
-
它的作用是什么:此类型的chunk用于提高连续malloc(small chunk)的效率,主要是提高内存分配的局部性。那么具体是怎么提高局部性的呢?举例说明。当用户请求一个small chunk,且该请求无法被small bin满足,那么就转而交由unsorted bin处理。同时,假设当前unsorted bin中只有一个chunk的话——就是last remainder chunk,那么就将该chunk分成两部分:前者分配给用户,剩下的部分放到unsorted bin中,并成为新的last remainder chunk。这样就保证了连续malloc(small chunk)中,各个small chunk在内存分布中是相邻的,即提高了内存分配的局部性。