对齐的 malloc C++ 实现

问题描述 投票:0回答:1

我找到了这段代码:

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 行。为什么要对偏移量求和两倍?

谢谢

c++ memory malloc heap-memory
1个回答
6
投票

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

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()

 版本。

© www.soinside.com 2019 - 2024. All rights reserved.