我找到了这段代码:
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;
}
这就是C++中对齐的malloc的实现。对齐的 malloc 是一个支持分配内存的函数,以便 返回的内存地址可以被特定的 2 的幂整除。 示例:
align_malloc(1000, 128) 将返回一个 128 的倍数的内存地址,该地址指向大小为 1000 字节的内存。
但我不明白第 4 行。为什么要对偏移量求和两倍?
谢谢
为什么要求和两倍的偏移量?
offset
并不完全求和两次。 第一次使用偏移量是为了分配大小:
void* p = (void * ) malloc(required_bytes + offset);
第二次是对齐:
void* q = (void * ) (((size_t)(p) + offset) & ~(alignment - 1));
说明:
~(alignment - 1)
是offset
的否定(记住,
int offset = alignment - 1;
),它为您提供满足对齐要求所需的掩码。从算术角度来说,添加偏移量并执行 按位与 (&
) 及其取反即可得到对齐指针的地址。
这个算术是如何工作的? 首先,记住对
malloc()
的内部调用是针对 required_bytes + offset
字节的。就像,不是您要求的对齐方式。例如,您想要分配 10 个字节,对齐方式为 16(因此 所需的行为是从可被 16 整除的地址开始分配 10 个字节)。所以上面的 malloc()
会给你 10+16-1
=25 个字节。不一定从能被 16 整除的正确地址开始。但是这个 16-1
是 0x000F
并且它的否定 (~
) 是 0xFFF0
。现在我们像这样应用按位和:p + 15 & 0xFFF0
这将使每个指针p
成为16的倍数。
但是等等,为什么首先要添加
alignment - 1
的偏移量? 你这样做是因为一旦你获得了 p
返回的地址 malloc()
,你不能做的一件事(为了找到最近的对齐地址)是在 before p
之前查找它——因为这将超出 malloc()
调用分配的内存范围,从 p
开始。为此,您首先要添加alignment - 1
,想一想,这正是您必须前进的最大值才能获得对齐。 * 感谢用户 DevSolar 提供一些额外的措辞。
注 1:要使这种方式发挥作用,对齐必须是 2 的幂。此代码片段不会强制执行这样的操作,因此可能会导致意外行为。
注 2:一个有趣的问题是,如何使用此函数的返回值来实现此类分配的
free()
版本。