我正在研究musl libc malloc
实现,我很难理解adjust_size
函数。
static int adjust_size(size_t *n)
{
/* Result of pointer difference must fit in ptrdiff_t. */
if (*n-1 > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) {
if (*n) {
errno = ENOMEM;
return -1;
} else {
*n = SIZE_ALIGN;
return 0;
}
}
*n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK;
return 0;
}
例如,在第一次比较中,为什么他们不只是与PTRDIFF_MAX
进行比较。无论如何,这似乎是上面评论的意图,为什么他们从*n
减去1,我认为(*n-1)
被比较为无符号而不是签名,所以他们正在处理案例其中*n
为0.但我不知道为什么在这种情况下将其作为无符号进行比较,因为看起来这两个职位在最后都会评估为签名数字。
另外,为什么如果它为0,他们会将*n
设置为SIZE_ALIGN
?我的理解是malloc应该返回NULL
或指针,如果size为0,它可以被传递给free而不会引起问题。
答案 0 :(得分:2)
为什么他们不只是与
进行比较PTRDIFF_MAX
大多数malloc
实现使用mmap
分别分配大块。因为mmap
在页面中分配内存,所以n
需要与页面边界(PAGE_SIZE
)对齐,另外还应包括块头(由SIZE_ALIGN
对齐)。< / p>
这就是为什么要对PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE
而不是PTRDIFF_MAX
进行比较的原因 - 以确保所有可能的未来对齐调整都不会导致块大小超过PTRDIFF_MAX
。< / p>
为什么他们会从
中减去1*n
因为n
可能会在以后像这样对齐:
n = (n + SIZE_ALIGN + PAGE_SIZE - 1) & -PAGE_SIZE;
结果值应小于或等于PTRDIFF_MAX
。值PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE + 1
仍然可以,因此减去1。
如果它为0
,为什么他们会将*n
设置为SIZE_ALIGN
因为调整后的块大小应该大于或等于SIZE_ALIGN
字节以适应OVERHEAD
字节的堆开销加上请求的数据区域应该能够适应稍后从free
使用的2个指针。稍后在代码中假定此对齐。
我认为
(*n-1)
被比较为无符号而不是 签名,所以他们正在处理*n
为0的情况。但我没有 知道为什么在这种情况下将其作为无符号进行比较 这两个职位最终都会评估签名数字。
我认为它可以写得更简单(虽然这可能不正确,我可能需要睡觉):
static int adjust_size(size_t *n)
{
if (*n > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE + 1) {
errno = ENOMEM;
return -1;
}
*n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK;
return 0;
}