对齐内存管理?

时间:2011-02-21 01:12:17

标签: c memory-management malloc alignment realloc

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

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

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

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

7 个答案:

答案 0 :(得分:19)

  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 mallocmalloc。没有例外。所以是的,你需要保留原始副本。

  3. 如果您已经有一个16字节对齐的类型,请参阅上面的(1)。

  4. 除此之外,你可能会发现你的malloc16实现无论如何都会为你提供16字节对齐的地址,尽管标准不能保证。如果您需要,可以随时实施自己的分配器。

    我自己,我会在malloc之上实现一个some padding for alignment (0-15 bytes) size of padding (1 byte) 16-byte-aligned area 图层,它将使用以下结构:

    malloc16()

    然后让你的malloc函数调用free16得到比请求大16个字节的块,弄清楚对齐区域应该在哪里,将填充长度放在那之前并返回地址对齐区域。

    对于free,您只需查看给定地址之前的字节以获取填充长度,从中计算出malloc'ed块的实际地址,并将其传递给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,它将地址加16,然后将低4位设置为0,实际上将其带回下一个最低对齐点({{1}保证它超过了maloc'ed区块的实际开始。)

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

答案 1 :(得分:1)

  1. 我不知道请求malloc返回内存的方式比平时更严格。对于Linux上的“通常”,来自man posix_memalign(如果你愿意,可以使用它而不是malloc()来获得更严格的对齐内存):

    GNU libc malloc()总是返回8字节对齐的内存地址,所以    只有在需要更大的对齐值时才需要这些例程。

  2. 必须 free()内存使用malloc(),posix_memalign()或realloc()返回的相同指针。

  3. 像往常一样使用realloc(),包括足够的额外空间,所以如果返回一个尚未对齐的新地址,你可以稍微memmove()它以对齐它。讨厌,但我能想到的最好。

答案 2 :(得分:1)

您可以编写自己的slab allocator来处理对象,它可以使用mmap一次分配页面,维护最近释放的地址缓存以便快速分配,为您处理所有对齐,并使您可以根据需要灵活地移动/增长对象。 malloc非常适合通用分配,但如果您了解数据布局和分配需求,则可以设计一个系统来完全满足这些要求。

答案 3 :(得分:1)

最棘手的要求显然是第三个要求,因为任何基于malloc() / realloc()的解决方案都是将realloc()移植到不同路线的人质。

在Linux上,您可以使用使用mmap()而不是malloc()创建的匿名映射。 mmap()返回的地址必须按页面对齐,映射可以使用mremap()进行扩展。

答案 4 :(得分:1)

启动C11,您有public static String smallestOfTwo(int[] n,int[] m) { Arrays.sort(n); Arrays.sort(m); for (int i = 0; i < n.length; i++) { if(n[i] < m[i]){ return "Array n"; }else if(n[i] > m[i]){ return "Array m"; } } return "both Array n & Array m are the same"; } 个原语,参数为:

对齐 - 指定对齐方式。必须是实现支持的有效对齐方式。 size - 要分配的字节数。对齐的整数倍

返回值

成功时,将指针返回到新分配的内存的开头。必须使用free()或 realloc ()取消分配返回的指针。

失败时,返回空指针。

示例

void *aligned_alloc( size_t alignment, size_t size );

可能的输出:

#include <stdio.h>
#include <stdlib.h>


    int main(void)
    {
        int *p1 = malloc(10*sizeof *p1);
        printf("default-aligned addr:   %p\n", (void*)p1);
        free(p1);

        int *p2 = aligned_alloc(1024, 1024*sizeof *p2);
        printf("1024-byte aligned addr: %p\n", (void*)p2);
        free(p2);
    }

答案 5 :(得分:0)

  1. 在您的系统上进行实验。在许多系统(尤其是64位系统)上,无论如何都可以从malloc()获得16字节对齐的内存。如果没有,你将不得不分配额外的空间并移动指针(几乎每台机器上最多8个字节)。

    例如,x86 / 64上的64位Linux有一个16字节long double,它是16字节对齐的 - 所以所有内存分配都是16字节对齐的。但是,对于32位程序,sizeof(long double)为8,内存分配仅为8字节对齐。

  2. 是 - 您只能free() malloc()返回的指针。其他任何东西都是灾难的秘诀。

  3. 如果您的系统执行16字节对齐的分配,则没有问题。如果没有,那么您将需要自己的重新分配器,它执行16字节对齐分配,然后复制数据 - 或使用系统realloc()并在必要时调整重新调整的数据。

  4. 仔细检查malloc()的手册页;可能有选项和机制来调整它,使其表现得如你所愿。

    在MacOS X上,有posix_memalign()valloc()(提供页面对齐的分配),并且man malloc_zoned_malloc标识了一系列“分区malloc”函数,标题为<malloc/malloc.h>

答案 6 :(得分:-1)

可能能够jimmy(在Microsoft VC ++和其他编译器中):

#pragma pack(16)

使malloc()被强制返回一个16字节对齐的指针。有点像:

ptr_16byte = malloc( 10 * sizeof( my_16byte_aligned_struct ));

如果它对malloc()起作用,我认为它也适用于realloc()。

只是一个想法。

- 皮特