我有一些关于管理对齐内存块的相关问题。跨平台的答案是理想的。但是,由于我非常确定不存在跨平台解决方案,因此我主要对Windows和Linux以及(在很大程度上)Mac OS和FreeBSD感兴趣。
在16字节边界上对齐大块内存的最佳方法是什么? (我知道使用malloc()
的简单方法,分配一些额外的空间,然后将指针碰到一个正确对齐的值。我希望能找到一些不那么重要的东西。 ,请参阅下面的其他问题。)
如果我使用普通的旧malloc()
,请分配额外的空间,然后将指针移动到正确对齐的位置,是否有必要将指针保持在块的开头为释放? (在指向块中间的指针上调用free()
似乎在Windows上实际运行,但我想知道标准是什么,即使标准说你做不到,它是否在实践中有效所有主要操作系统。我不关心模糊的DS9K - 就像操作系统一样。)
这是硬/有趣的部分。在保持对齐的同时重新分配内存块的最佳方法是什么?理想情况下,这比调用malloc()
,复制,然后在旧块上调用free()
更聪明。我想尽可能在适当的地方做。
答案 0 :(得分:19)
如果您的实现具有需要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
。malloc
。没有例外。所以是的,你需要保留原始副本。
如果您已经有一个16字节对齐的类型,请参阅上面的(1)。
除此之外,你可能会发现你的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)
我不知道请求malloc返回内存的方式比平时更严格。对于Linux上的“通常”,来自man posix_memalign(如果你愿意,可以使用它而不是malloc()来获得更严格的对齐内存):
GNU libc malloc()总是返回8字节对齐的内存地址,所以 只有在需要更大的对齐值时才需要这些例程。
你必须 free()内存使用malloc(),posix_memalign()或realloc()返回的相同指针。
像往常一样使用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)
在您的系统上进行实验。在许多系统(尤其是64位系统)上,无论如何都可以从malloc()
获得16字节对齐的内存。如果没有,你将不得不分配额外的空间并移动指针(几乎每台机器上最多8个字节)。
例如,x86 / 64上的64位Linux有一个16字节long double
,它是16字节对齐的 - 所以所有内存分配都是16字节对齐的。但是,对于32位程序,sizeof(long double)
为8,内存分配仅为8字节对齐。
是 - 您只能free()
malloc()
返回的指针。其他任何东西都是灾难的秘诀。
如果您的系统执行16字节对齐的分配,则没有问题。如果没有,那么您将需要自己的重新分配器,它执行16字节对齐分配,然后复制数据 - 或使用系统realloc()
并在必要时调整重新调整的数据。
仔细检查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()。
只是一个想法。
- 皮特