对齐的 malloc C++ 实现

hte*_*teo 3 c++ memory malloc heap-memory

我找到了这段代码:

void* aligned_malloc(size_t required_bytes, size_t alignment) {
int offset = alignment - 1;
void* P = (void * ) malloc(required_bytes + offset);
void* q = (void * ) (((size_t)(p) + offset) & ~(alignment - 1));
return q;
}
Run Code Online (Sandbox Code Playgroud)

这就是C++中对齐的malloc的实现。对齐的 malloc 是一个支持分配内存的函数,使得返回的内存地址可以被特定的 2 的幂整除。例子:

align_malloc(1000, 128) 将返回一个 128 的倍数的内存地址,该地址指向大小为 1000 字节的内存。

但我不明白第 4 行。为什么要对偏移量求和两倍?

谢谢

Rei*_*ica 7

为什么要对偏移量求和两倍?

offset并不完全是被求和两次。第一次使用偏移量是为了分配大小:

void* p = (void * ) malloc(required_bytes + offset);
Run Code Online (Sandbox Code Playgroud)

第二次是为了对齐:

void* q = (void * ) (((size_t)(p) + offset) & ~(alignment - 1));
Run Code Online (Sandbox Code Playgroud)

解释: ~(alignment - 1)是(记住,)的否定,它为您提供满足对齐请求所需的掩码。从算术角度来说,添加偏移量并按位与( ) 及其取反即可得到对齐指针的地址。offsetint offset = alignment - 1;&

这个算术是如何运作的?首先,请记住,内部调用malloc()是针对required_bytes + offset字节的。就像,不是您要求的对齐方式。例如,您想要分配对齐为 16 的 10 个字节(因此所需的行为是从可被 16 整除的地址开始分配 10 个字节)。所以malloc()上面的结果将为您提供10+16-1=25 个字节。不一定从能被 16 整除的正确地址开始。但是,这16-10x000F,它的否定 ( ~) 是0xFFF0。现在我们像这样应用按位与p + 15 & 0xFFF0:这将使每个指针p都是 16 的倍数。

alignment - 1但是等等,为什么首先添加这个偏移量呢?p这样做是因为一旦获得返回的地址malloc()您不能做的一件事(为了找到最近的对齐地址)就是之前 p查找它- 因为这将超出调用分配的内存范围malloc(),从p。为此,您首先添加 alignment - 1,考虑一下,这正是您必须前进才能获得对齐的最大值。

* 感谢用户 DevSolar 提供的一些额外措辞。

注 1:要使这种方式发挥作用,对齐方式必须是 2 的幂。此代码片段不会强制执行这样的操作,因此可能会导致意外行为。

注 2:一个有趣的问题是如何使用free()该函数的返回值来实现此类分配的版本。

  • @hteo:这里的主要思想是这样的:要获得align-16,您可能必须将地址向前移动最多15个字节。这是额外分配的“align - 1”值,因为您只能向前移动,而不能向后移动。然后通过添加最大值并通过应用该位掩码“四舍五入”来“获取”对齐地址。 (3认同)