为什么 malloc 总是多分配内存?
Why malloc always does more than I asked for?

当你调用 malloc(13) 时,真的只拿到了 13 字节吗?其实远不止如此。为了支持 free() 和内存对齐,分配器必须在用户内存前后塞入 Header、Back Pointer 和 Padding。这些元数据让内存布局变得复杂,也导致了 Internal Fragmentation。文章通过从零构建一个简单的分配器,揭示了从 Bump Allocator 到 Free List 的演变,解释了为什么那些看似浪费的 Padding 字节对系统至关重要,以及它们为何无法被复用。
那些位于元数据和实际对象之间的 Padding 字节,在整个分配生命周期中都只是闲置在那里,无法被复用。
HN 评论区
46- phire
> 所以 alloc() 不仅仅需要返回一个指针。它需要返回一个指针,该指针的对齐方式必须正确,以匹配调用者即将存储的数据类型。
Malloc 不知道所需的对齐方式(因为它完全不知道类型是什么,一切都被强制转换为 void)。因此,所有的 malloc 实现都有一个最小对齐保证。如今在 x86 上通常是 16 字节,因为这意味着即使是 128 位的 SSE 值默认也会对齐。
无论如何,你也不能低于 sizeof(void*),因为回指指针(backpointer)本身也需要对齐。
只有当你使用 memalign 或 aligned_malloc 指定更大的对齐方式时,才会出现填充。
- CodesInChaos
你的 bump 分配器在请求的分配足够大时,会因为整数溢出而变成缓冲区溢出:
if (a->cursor + size > a->limit) return NULL; // 内存不足
我会这样重写:
if (size > a->limit - a->cursor) return NULL; // 内存不足
- lexicality
我有点困惑。我们最初是:
[ 头部 ][ ...变量填充... ][ 回指指针 ][ 用户内存 ]
^ 始终正好是 sizeof(void*)
字节位于用户内存之前,
无论之前有多少填充。
然后文章说我们不需要对齐回指指针,结果变成了:
[ 头部 ][ 回指指针 ][ 填充 ][ 用户内存 ]
但没有清楚解释,如果回指指针位于可变对齐之后,我们该如何访问它。
- drivebyhooting
为什么还要搞动态填充和回指指针?这至少浪费了 8 个字节。
你不如始终对齐到 8 字节,并把你的头部做成 8 的倍数。
- pjmlp
像《The C/C++ Users' Journal》和《DDJ》这样的老杂志以前经常刊登销售 malloc()/free() 替换库的公司广告,原因正是单一的实现无法满足所有场景。