关于管理对齐的内存块,我有一些相关的问题 . 跨平台的答案是理想的 . 但是,由于我非常确定不存在跨平台解决方案,因此我主要对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 回答
最棘手的要求显然是第三个,因为任何基于
malloc()
/realloc()
的解决方案都是realloc()
将块移动到不同的对齐方式 .在Linux上,您可以使用匿名使用
mmap()
而不是malloc()
创建的映射 . 由mmap()
返回的地址必须是页面对齐的,并且映射可以使用mremap()
进行扩展 .GNU libc malloc()始终返回8字节对齐的内存地址,因此只有在需要更大的对齐值时才需要这些例程 .
必须使用malloc(),posix_memalign()或realloc()返回的相同指针释放()内存 .
像往常一样使用realloc(),包括足够的额外空间,所以如果返回一个尚未对齐的新地址,你可以稍微memmove()它以对齐它 . 讨厌,但我能想到的最好 .
如果您的实现具有需要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
层,它将使用以下结构:然后让
malloc16()
函数调用malloc
得到比请求大16个字节的块,找出对齐区域应该在哪里,在此之前放置填充长度并返回对齐区域的地址 .对于
free16
,您只需查看给定地址之前的字节以获取填充长度,从中计算出malloc'ed块的实际地址,并将其传递给free
.这是未经测试但应该是一个好的开始:
malloc16
中的魔术线是p = (porig + 16) & (~0xf);
,它将地址加16,然后将低4位设置为0,实际上将它带回到下一个最低对齐点(+16
保证它超过了maloc'ed块的实际开始) .现在,我并不认为上面的代码只是kludgey . 你必须在感兴趣的平台上测试它,看看它是否可行 . 它的主要优点是它抽象了丑陋的一点,所以你永远不必担心它 .
您可以编写自己的slab allocator来处理对象,它可以使用_1689880一次分配页面,维护最近释放的地址缓存以进行快速分配,为您处理所有对齐,并为您提供移动/增长对象的灵活性完全按照你的需要 .
malloc
非常适合通用分配,但如果您了解数据布局和分配需求,则可以设计一个系统来完全满足这些要求 .启动C11,您有
void *aligned_alloc( size_t alignment, size_t size );
基元,其中参数为:alignment - 指定对齐方式 . 必须是实现支持的有效对齐方式 . size - 要分配的字节数 . 对齐的整数倍
Return value
成功时,返回指向新分配内存开头的指针 . 必须使用free()或realloc()释放返回的指针 .
失败时,返回空指针 .
Example :
Possible output:
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>
.您可能能够使用jimmy(在Microsoft VC和其他编译器中):
#pragma pack(16)
这样malloc()被强制返回一个16字节对齐的指针 . 有点像:
ptr_16byte = malloc( 10 * sizeof( my_16byte_aligned_struct ));
如果它对malloc()起作用,我认为它也适用于realloc() .
只是一个想法 .