ptmalloc2 中为非主 Arena 分配新堆段的核心函数。它通过 mmap 向操作系统申请一块内存,并在其上初始化 heap_info 结构体,然后将其挂接到 Arena 的堆段链表中。
函数签名
static heap_info *
alloc_new_heap (size_t size, size_t top_pad, size_t pagesize,
int mmap_flags)
参数说明:
| 参数 | 含义 |
|---|---|
size | 请求的堆段大小(用于分配 chunk 的空间) |
top_pad | Top Chunk 填充量(默认 128KB) |
pagesize | 系统页大小(通常 4KB) |
mmap_flags | mmap 的标志位(如 MAP_PRIVATE | MAP_ANONYMOUS) |
核心逻辑拆解
1. 计算实际需要映射的大小
size = ALIGN_UP (size + top_pad + sizeof (heap_info), pagesize);
-
size:请求的 chunk 空间。 -
top_pad:额外的填充量,减少后续扩展频率。 -
sizeof(heap_info):heap_info结构体本身占用的空间。 -
ALIGN_UP(..., pagesize):向上对齐到页边界,因为mmap要求页对齐。
2. 尝试不同的 mmap 标志组合
if (mmap_flags & MAP_HUGETLB)
{
// 尝试使用大页
mm = (char *) MMAP (0, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0);
if (mm != MAP_FAILED)
goto success;
}
// 回退到普通页
mm = (char *) MMAP (0, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (mm == MAP_FAILED)
return 0;
-
如果请求了
MAP_HUGETLB,先尝试用大页映射。 -
如果大页失败,回退到普通页。
-
如果普通页也失败,返回
0(分配失败)。
3. 初始化 heap_info
success: h = (heap_info *) mm; h->size = size; h->mprotect_size = size; h->ar_ptr = NULL; // 稍后由调用者设置 h->prev = NULL; // 稍后由调用者设置 return h;
-
h->size:记录堆段的总大小。 -
h->mprotect_size:记录已设置内存保护的大小。 -
h->ar_ptr和h->prev:由调用者(new_heap或grow_heap)后续设置。
调用者:new_heap
alloc_new_heap 通常被 new_heap 调用,后者负责将新堆段挂接到 Arena:
static heap_info *
new_heap (size_t size, size_t top_pad)
{
heap_info *h = alloc_new_heap (size, top_pad, GLRO (dl_pagesize), 0);
if (h == NULL)
return NULL;
// 设置 heap_info 的 ar_ptr 和 prev
h->ar_ptr = ...;
h->prev = ...;
return h;
}
与 grow_heap 的区别
| 函数 | 作用 | 是否创建新堆段 |
|---|---|---|
alloc_new_heap | 通过 mmap 分配全新的堆段 | ✅ 是 |
grow_heap | 通过 mprotect 扩展现有堆段的可写区域 | ❌ 否 |
new_heap | 调用 alloc_new_heap,并初始化堆段信息 | ✅ 是 |
注意事项
-
mmap失败处理:如果mmap返回MAP_FAILED,函数返回0,调用者需要处理。 -
大页回退:如果请求了大页但失败,会回退到普通页。这是为了兼容不支持大页的系统。
-
ar_ptr和prev未初始化:alloc_new_heap只负责分配和初始化size和mprotect_size,ar_ptr和prev由调用者设置。 -
页对齐:
size必须向上对齐到pagesize,否则mmap会失败。 -
top_pad的作用:额外的填充量,减少后续grow_heap的频率。默认 128KB。
总结
| 要点 | 说明 |
|---|---|
| 功能 | 通过 mmap 为非主 Arena 分配新堆段 |
| 大小计算 | size + top_pad + sizeof(heap_info),向上对齐到页 |
| 大页支持 | 如果请求 MAP_HUGETLB,先尝试大页,失败回退普通页 |
| 初始化 | 设置 heap_info 的 size 和 mprotect_size |
| 调用者 | new_heap 负责设置 ar_ptr 和 prev |
与 grow_heap 区别 | alloc_new_heap 创建新堆段,grow_heap 扩展现有堆段 |
一句话理解:
alloc_new_heap是 ptmalloc2 为非主 Arena “开疆拓土”的函数。它通过mmap向操作系统申请一块新的、页对齐的内存,在上面初始化heap_info结构体,然后返回给调用者。调用者再将它挂接到 Arena 的堆段链表中,成为该 Arena 新的可用内存来源。

1541

被折叠的 条评论
为什么被折叠?



