这个宏定义了 Unsorted Bin 的入口。它用 bin_at(M, 1) 获取第 1 号 bin 的哨兵节点地址,而这个 bin 就是专门用来存放“未排序”空闲 chunk 的容器。
源码定义
/* The otherwise unindexable 1-bin is used to hold unsorted chunks. */
#define unsorted_chunks(M) (bin_at (M, 1))
逐步拆解
1. bin_at(M, 1)
回顾 bin_at 的定义:
#define bin_at(m, i) \\
(mbinptr)(((char *)&((m)->bins[((i) – 1) * 2])) – \\
offsetof(struct malloc_chunk, fd))
当 i = 1 时:
(i – 1) * 2 = 0
bin_at(M, 1) = (char *)&M->bins[0] – offsetof(malloc_chunk, fd)
也就是说,bin_at(M, 1) 返回的是 bins[0] 和 bins[1] 组成的“虚拟 chunk”的起始地址。
2. 为什么是“otherwise unindexable”?
注释说“otherwise unindexable”(原本无法被索引的),是因为:
-
bins 数组的索引 0 在逻辑上被保留,不对应任何常规大小的 bin。
-
常规的 Small Bin 从 i = 2 开始,Large Bin 从 i = 64 开始。
-
如果不用 i = 1 来存放 Unsorted Bin,那么 bins[0] 和 bins[1] 这两个数组元素就会被浪费。
所以 ptmalloc2 巧妙地把 i = 1 这个“空位”分配给了 Unsorted Bin,让它有一个合法的“家”。
Unsorted Bin 的用途
Unsorted Bin 是 ptmalloc2 中的中转站,主要承担以下职责:
| 释放 chunk | 不直接放入 Small/Large Bin,而是先放入 Unsorted Bin |
| 分配 chunk | 优先遍历 Unsorted Bin,寻找合适的块 |
| 整理 | 遍历时,将不符合需求的块“分拣”到对应的 Small/Large Bin |
关键特性:
-
只有一个 Unsorted Bin,大小不分类。
-
所有放入其中的 chunk 大小无序。
-
采用 LIFO(后进先出) 策略,最近释放的块最先被检查。
与其他宏的关系
| unsorted_chunks(M) | bin_at(M, 1) | Unsorted Bin |
| bin_at(M, i) | i = 2~63 | Small Bin |
| bin_at(M, i) | i = 64~126 | Large Bin |
| bin_at(M, 127) | 保留未使用 | – |
访问方式:
// 获取 Unsorted Bin 的哨兵
mbinptr unsorted = unsorted_chunks(av);
// 遍历 Unsorted Bin
for (victim = unsorted->fd; victim != unsorted; victim = victim->fd) {
// 处理每个 chunk
}
在内存布局中的位置
bins 数组:
┌─────────────────────────────────────────────┐
│ bins[0] │ bins[1] │ bins[2] │ bins[3] │ … │
│ fd │ bk │ fd │ bk │ │
└─────────────────────────────────────────────┘
↑
│
unsorted_chunks(M) = bin_at(M, 1)
指向 bins[0] – offsetof(fd) 的位置
即虚拟 chunk 的起始地址
逻辑 bin 索引:
┌─────────────────────────────────────────────┐
│ i=1 │ i=2 │ i=3 │ … │ i=127 │
│Unsorted │Small 1 │Small 2 │ │ 保留 │
└─────────────────────────────────────────────┘
注意事项
i 从 1 开始,不是 0:这是 bin_at 的设计约定。i = 1 对应 bins[0] 和 bins[1]。
Unsorted Bin 只有一个:不像 Small/Large Bin 有多个,Unsorted Bin 是唯一的。
遍历终止条件:victim != unsorted,因为它是循环双向链表。
unsorted_chunks 是宏,不是函数:它在编译时展开,没有运行时开销。
总结
| 功能 | 获取 Unsorted Bin 的哨兵节点地址 |
| 定义 | bin_at(M, 1) |
| 位置 | bins[0] 和 bins[1] |
| 为什么是 1 | 索引 0 在逻辑上被保留,用 1 来存放 Unsorted Bin |
| 用途 | 作为释放和分配之间的中转站,延迟排序 |
| 遍历 | 从 unsorted->fd 开始,直到回到 unsorted |
一句话理解:
unsorted_chunks(M) 就是 Unsorted Bin 的“门牌号”。它利用 bins 数组中原本无法被索引的第 1 号位置,为未排序的空闲 chunk 提供了一个临时的家。所有释放的块先来这里“报到”,等待被分拣到正确的 Small 或 Large Bin 中。


