我有几个关于管理对齐内存块的相关问题。跨平台的答案将是理想的。但是,由于我非常确定不存在跨平台解决方案,因此我主要对 Windows 和 Linux 感兴趣,对 Mac OS 和 FreeBSD 的(程度)较小。
让一 block 内存在 16 字节边界上对齐的最佳方法是什么? (我知道使用
malloc()
的简单方法,分配一点额外的空间,然后将指针向上移动到正确对齐的值。我希望能少一些困惑-不过,是的。另外,请参阅下面的其他问题。)如果我使用普通的旧
malloc()
,分配额外的空间,然后将指针向上移动到正确对齐的位置,是否有必要将指针保持在开头释放周围的 block ? (在指向 block 中间的指针上调用free()
似乎在 Windows 上实际上有效,但我想知道标准是怎么说的,即使标准说你不能,是否它实际上适用于所有主要操作系统。我不关心晦涩难懂的 DS9K -就像操作系统一样。)这是困难/有趣的部分。在保持对齐的同时重新分配内存块的最佳方法是什么?理想情况下,这比调用
malloc()
、复制然后在旧 block 上调用free()
更智能。我想尽可能就地进行。
最佳答案
如果您的实现具有需要 16 字节对齐的标准数据类型(例如
long long
),malloc
已经保证您返回的 block 将是正确对齐。 C99 的第 7.20.3 节指出如果分配成功则返回的指针适当对齐,以便它可以分配给指向任何类型对象的指针。
您必须将与
malloc
给您的地址完全相同的地址传回free
。没有异常(exception)。所以是的,您需要保留原件。如果您已经有 16 字节对齐要求的类型,请参阅上面的 (1)。
除此之外,您可能会发现您的 malloc
实现无论如何都会为您提供 16 字节对齐的地址以提高效率,尽管标准并不能保证这一点。如果需要,您始终可以实现您的自己的分配器。
我自己,我将在 malloc
之上实现一个 malloc16
层,该层将使用以下结构:
some padding for alignment (0-15 bytes)
size of padding (1 byte)
16-byte-aligned area
然后让你的 malloc16()
函数调用 malloc
得到一个比请求大 16 字节的 block ,找出对齐区域应该在哪里,把填充长度放在刚刚好在此之前返回对齐区域的地址。
对于 free16
,您只需查看给定地址之前的字节以获得填充长度,从中计算出 malloc block 的实际地址,并将其传递给 免费
。
这是未经测试的,但应该是一个好的开始:
void *malloc16 (size_t s) {
unsigned char *p;
unsigned char *porig = malloc (s + 0x10); // allocate extra
if (porig == NULL) return NULL; // catch out of memory
p = (porig + 16) & (~0xf); // insert padding
*(p-1) = p - porig; // store padding size
return p;
}
void free16(void *p) {
unsigned char *porig = p; // work out original
porig = porig - *(porig-1); // by subtracting padding
free (porig); // then free that
}
malloc16
中的魔法行是 p = (porig + 16) & (~0xf);
它将地址加 16 然后将低 4 位设置为0,实际上将它带回到下一个最低对齐点(+16
保证它已经过了 maloc block 的实际开始)。
现在,我并不是说上面的代码是什么而是杂七杂八的东西。您必须在感兴趣的平台上对其进行测试,看看它是否可行。它的主要优点是它抽象掉了丑陋的部分,因此您永远不必担心它。
关于c - 对齐内存管理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5061392/