我试图了解什么功能memalign()
和posix_memalign()
做什么。阅读可用的文档没有帮助。
有人可以帮助我了解它的工作原理以及它的用途吗?或者,也许提供一个使用示例?
我试图了解 linux 内存是如何工作的,我需要编写自己的简单内存池(低碎片堆)。
我试图了解什么功能memalign()
和posix_memalign()
做什么。阅读可用的文档没有帮助。
有人可以帮助我了解它的工作原理以及它的用途吗?或者,也许提供一个使用示例?
我试图了解 linux 内存是如何工作的,我需要编写自己的简单内存池(低碎片堆)。
虽然malloc
为您提供了一块可以进行任何对齐的内存(唯一的要求是它必须与实现支持的最大原始类型对齐),但posix_memalign
为您提供了一块保证具有请求对齐的内存。
因此 eg 的结果posix_memalign(&p, 32, 128)
将是一个 128 字节的内存块,其起始地址保证为 32 的倍数。
这对于需要遵循特定对齐的内存的各种低级操作(例如使用 SSE 指令或 DMA)很有用。
malloc
总是返回设置为任何原始类型所需的最大对齐的内存。这允许malloc
'd 内存存储您可能需要的任何类型。我对 , 的描述的理解posix_memalign
是它返回一个内存位置,其地址将是您指定为对齐的任何内容的倍数。
我不确定这在编写自定义内存池时会有多大用处,但我已经尝试提供了一个如何实现它的示例。不同之处在于我的例子,任何分配的东西malloc_aligned
都必须用free_aligned
;释放。但是,posix_memalign
您可以使用free
.
#include <stdlib.h>
#include <stdio.h>
void *malloc_aligned(size_t alignment, size_t bytes)
{
// we need to allocate enough storage for the requested bytes, some
// book-keeping (to store the location returned by malloc) and some extra
// padding to allow us to find an aligned byte. im not entirely sure if
// 2 * alignment is enough here, its just a guess.
const size_t total_size = bytes + (2 * alignment) + sizeof(size_t);
// use malloc to allocate the memory.
char *data = malloc(sizeof(char) * total_size);
if (data)
{
// store the original start of the malloc'd data.
const void * const data_start = data;
// dedicate enough space to the book-keeping.
data += sizeof(size_t);
// find a memory location with correct alignment. the alignment minus
// the remainder of this mod operation is how many bytes forward we need
// to move to find an aligned byte.
const size_t offset = alignment - (((size_t)data) % alignment);
// set data to the aligned memory.
data += offset;
// write the book-keeping.
size_t *book_keeping = (size_t*)(data - sizeof(size_t));
*book_keeping = (size_t)data_start;
}
return data;
}
void free_aligned(void *raw_data)
{
if (raw_data)
{
char *data = raw_data;
// we have to assume this memory was allocated with malloc_aligned.
// this means the sizeof(size_t) bytes before data are the book-keeping
// which points to the location we need to pass to free.
data -= sizeof(size_t);
// set data to the location stored in book-keeping.
data = (char*)(*((size_t*)data));
// free the memory.
free(data);
}
}
int main()
{
char *ptr = malloc_aligned(7, 100);
printf("is 5 byte aligned = %s\n", (((size_t)ptr) % 5) ? "no" : "yes");
printf("is 7 byte aligned = %s\n", (((size_t)ptr) % 7) ? "no" : "yes");
free_aligned(ptr);
return 0;
}
除了奥利的回答,我想指出一个更重要的问题。
在最近的 x86 体系结构中,缓存线是 64 字节,它是可以从内存获取到缓存的最小数据量。假设你的结构大小是 56 字节,你有一个很大的数组。当您查找一个元素时,CPU 将需要发出 2 个内存请求(即使它位于高速缓存行的中间,它也可能会发出 2 个请求)。这对性能不利,因为您必须等待内存,并且使用更多缓存,最终导致更高的缓存未命中率。在这种情况下,仅使用 posix_memalign 是不够的,但您应该填充或压缩您的结构,使其位于 64 字节边界上。
拥有 40 字节的结构只是运气不好:)
它如何工作取决于实现。该函数的目的是为您提供一个 n 字节对齐的内存块(块的起始地址是 n 的乘积)。
由于 memalign 已过时(参考:手册页),此处仅描述 malloc() 和 posix_memalign() 之间的区别。malloc() 是 8 字节对齐的(例如,对于 RHEL 32 位),但对于 posix_memalign(),对齐是用户可定义的。要知道它的用途,也许一个很好的例子是使用 mprotect() 设置内存属性。要使用 mprotect(),内存指针必须是 PAGE 对齐的。因此,如果您以 pagesize 作为对齐方式调用 posix_memalign(),则返回的指针可以轻松提交给 mprotect() 以设置读写可执行属性。(例如,将数据复制到内存指针后,可以将其设置为只读属性以防止其被修改)。“malloc()”的返回指针不能在这里使用。
当您在GNU C中使用posix_memalign时,您应该注意第二个参数不仅应该是 2 的幂,而且应该是 sizeof (void*) 的倍数。请注意,此要求与 memalign 函数中的要求不同,后者仅需要 2 的幂。
int
__posix_memalign (void **memptr, size_t alignment, size_t size)
{
void *mem;
/* Test whether the SIZE argument is valid. It must be a power of
two multiple of sizeof (void *). */
if (alignment % sizeof (void *) != 0
|| !powerof2 (alignment / sizeof (void *))
|| alignment == 0)
return EINVAL;
void *address = RETURN_ADDRESS (0);
mem = _mid_memalign (alignment, size, address);
if (mem != NULL)
{
*memptr = mem;
return 0;
}
return ENOMEM;
}
weak_alias (__posix_memalign, posix_memalign)
当我们查看 posix_memalign 实现中的第一个 if 条件时,它检查对齐是否是 sizeof(void*) 的倍数。