首页 文章

对齐内存管理?

提问于
浏览
21

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

  • 's the best way of getting a chunk of memory aligned on 16-byte boundaries? (I'了解使用 malloc() 的简单方法,分配一点额外空间然后将指针碰到正确对齐的值 . 不过,我希望能找到一些不那么重要的东西 . 另外,请参阅下面的其他问题 . )

  • 如果我使用普通的旧 malloc() ,分配额外的空间,然后将指针移动到正确对齐的位置,是否有必要将指针保持在块的开头以便释放? (在指向块中间的指针上调用 free() 似乎在Windows上实际运行,但是我是否在所有主要操作系统上都能正常工作's. I don't关注模糊的DS9K-like OS . )

  • This is the hard/interesting part . 在保持对齐的同时重新分配内存块的最佳方法是什么?理想情况下,这将比调用 malloc() ,复制,然后在旧块上调用 free() 更智能 . 我想尽可能在适当的地方做 .

7 回答

  • 1

    最棘手的要求显然是第三个,因为任何基于 malloc() / realloc() 的解决方案都是 realloc() 将块移动到不同的对齐方式 .

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

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

    GNU libc malloc()始终返回8字节对齐的内存地址,因此只有在需要更大的对齐值时才需要这些例程 .

    • 必须使用malloc(),posix_memalign()或realloc()返回的相同指针释放()内存 .

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

  • 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.

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

    • 如果您已经有一个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个字节的块,找出对齐区域应该在哪里,在此之前放置填充长度并返回对齐区域的地址 .

    对于 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
    }
    

    malloc16 中的魔术线是 p = (porig + 16) & (~0xf); ,它将地址加16,然后将低4位设置为0,实际上将它带回到下一个最低对齐点( +16 保证它超过了maloc'ed块的实际开始) .

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

  • 0

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

  • -1

    启动C11,您有 void *aligned_alloc( size_t alignment, size_t size ); 基元,其中参数为:

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

    Return value

    成功时,返回指向新分配内存开头的指针 . 必须使用free()或realloc()释放返回的指针 .

    失败时,返回空指针 .

    Example

    #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);
        }
    

    Possible output:

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

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

    • 是 - 你只能通过 malloc() 返回的指针 free() . 其他任何东西都是灾难的秘诀 .

    • 如果你的系统进行了16字节对齐的分配,那么就没有't a problem. If it doesn' t,那么你需要你自己的重新分配器,它进行16字节对齐分配,然后复制数据 - 或者使用系统 realloc() 并调整重新分配的数据必要时 .

    仔细检查 malloc() 的手册页;可能有选项和机制来调整它,使其行为符合您的要求 .

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

  • 1

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

    #pragma pack(16)

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

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

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

    只是一个想法 .

    • 皮特

相关问题