dsi*_*cha 21 c malloc memory-management alignment realloc
关于管理对齐的内存块,我有一些相关的问题.跨平台的答案是理想的.但是,由于我非常确定不存在跨平台解决方案,因此我主要对Windows和Linux以及(在很大程度上)Mac OS和FreeBSD感兴趣.
在16字节边界上对齐大块内存的最佳方法是什么?(我知道使用琐碎的方法malloc()
,分配一些额外的空间,然后将指针碰到一个正确对齐的值.虽然我希望能找到更少的东西.另外,请参阅下面的其他内容的问题.)
如果我使用普通旧的malloc()
,分配额外的空间,然后将指针移动到正确对齐的位置,是否有必要将指针保持在块的开头以便释放?(调用free()
指向块中间的指针似乎在Windows上实际运行,但我想知道标准是什么,即使标准说你不能,它是否在所有主要操作系统的实践中都有效.我不关心模糊的DS9K操作系统.)
这是一个艰难/有趣的部分.在保持对齐的同时重新分配内存块的最佳方法是什么?理想情况下,这将比调用malloc()
,复制,然后调用free()
旧块更智能.我想尽可能在适当的地方做.
pax*_*blo 20
如果您的实现具有需要16字节对齐的标准数据类型(long long
例如),则malloc
已经保证返回的块将正确对齐.C99第7.20.3节规定The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object.
您必须将完全相同的地址传回free
给您malloc
.没有例外.所以是的,你需要保留原始副本.
如果您已经有一个16字节对齐的类型,请参阅上面的(1).
除此之外,您可能会发现,malloc
无论如何,您的实现都会为您提供16字节对齐的地址以提高效率,但标准并不能保证这一点.如果需要,可以随时实现自己的分配器.
我自己,我将malloc16
在其上实现一个层malloc
将使用以下结构:
some padding for alignment (0-15 bytes)
size of padding (1 byte)
16-byte-aligned area
Run Code Online (Sandbox Code Playgroud)
然后malloc16()
调用函数malloc
以获得比请求大16个字节的块,找出对齐区域应该在哪里,在此之前放置填充长度并返回对齐区域的地址.
因为free16
,您只需查看给定地址之前的字节以获取填充长度,从中计算出malloc'ed块的实际地址,并将其传递给free
.
这是未经测试但应该是一个好的开始:
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
}
Run Code Online (Sandbox Code Playgroud)
魔术线在malloc16
IS p = (porig + 16) & (~0xf);
这增加16到地址然后将低4位为0时,在效果将它回复到下一个最低的对准点(+16
保证它是过去的maloc'ed块的实际开始).
现在,我并不认为上面的代码只是 kludgey.你必须在感兴趣的平台上测试它,看看它是否可行.它的主要优点是它抽象了丑陋的一点,所以你永远不必担心它.