对齐内存管理?

dsi*_*cha 21 c malloc memory-management alignment realloc

关于管理对齐的内存块,我有一些相关的问题.跨平台的答案是理想的.但是,由于我非常确定不存在跨平台解决方案,因此我主要对Windows和Linux以及(在很大程度上)Mac OS和FreeBSD感兴趣.

  1. 在16字节边界上对齐大块内存的最佳方法是什么?(我知道使用琐碎的方法malloc(),分配一些额外的空间,然后将指针碰到一个正确对齐的值.虽然我希望能找到更少的东西.另外,请参阅下面的其他内容的问题.)

  2. 如果我使用普通旧的malloc(),分配额外的空间,然后将指针移动到正确对齐的位置,是否有必要将指针保持在块的开头以便释放?(调用free()指向块中间的指针似乎在Windows上实际运行,但我想知道标准是什么,即使标准说你不能,它是否在所有主要操作系统的实践中都有效.我不关心模糊的DS9K操作系统.)

  3. 这是一个艰难/有趣的部分.在保持对齐的同时重新分配内存块的最佳方法是什么?理想情况下,这将比调用malloc(),复制,然后调用free()旧块更智能.我想尽可能在​​适当的地方做.

pax*_*blo 20

  1. 如果您的实现具有需要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.

  2. 必须将完全相同的地址传回free给您malloc.没有例外.所以是的,你需要保留原始副本.

  3. 如果您已经有一个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)

魔术线在malloc16IS p = (porig + 16) & (~0xf);这增加16到地址然后将低4位为0时,在效果将它回复到下一个最低的对准点(+16保证它是过去的maloc'ed块的实际开始).

现在,我并不认为上面的代码只是 kludgey.你必须在感兴趣的平台上测试它,看看它是否可行.它的主要优点是它抽象了丑陋的一点,所以你永远不必担心它.

  • 来自Linux上的man posix_memalign:"GNU libc malloc()总是返回8字节对齐的内存地址".Re 7.20.3 - 任何指针的对齐并不意味着它必须是16个字节. (2认同)
  • @Tony,如果你有一个16字节对象需要16字节对齐,malloc是_required_给你一个满足这个要求的地址.它没有对齐指针,它正在对齐可以指向的对象. (2认同)
  • @paxdiablo:C语言要求`malloc`返回一个适当对齐的指针,仅适用于C语言范围内存在的类型.例如,如果OP使用SSE指令编写asm,则可能需要更大的对齐,当然,提供它不是C实现的责任.此外,OP可能需要符合(例如)28位的指针,以便与指针紧密地打包其他数据.:-) (2认同)