我目前正在一台 NUMA 机器上工作。我正在使用
numa_free
来释放分配的内存。然而,与 free
不同,numa_free
需要知道要释放多少字节。有没有办法知道指针指向了多少字节而不用追踪它?
底层API无法获取内存大小。您必须记住在某处分配期间的大小。例如,您可以编写自己的分配器,它分配 4 个额外字节,存储缓冲区的前 4 个字节大小,并且在释放期间您可以从中读取缓冲区的大小:
void *my_alloc(size_t size)
{
void *buff = numa_alloc_local( size + sizeof(size_t) );
if (buff == 0) return 0;
*(size_t *)buff = size;
return buff + sizeof(size_t);
}
void my_free(void *buf)
{
numa_free(buf - sizeof(size_t), *(size_t *)(buf - sizeof(size_t)));
}
将分配大小存储在报告的内存指针之前。
@light_keeer有一个很好的解决方案/方法,但存在潜在的对齐问题@pdw。
my2_alloc()
,与malloc()
一样,可能返回一个满足C规范对齐要求的指针。 同样,my2_alloc()
也需要确保返回的指针满足对齐要求。
如果分配成功,则返回的指针是适当对齐的,以便可以将其分配给指向具有基本对齐要求的任何类型对象的指针...
C11dr §7.22.3 内存管理函数基本对齐由小于或等于所有上下文中实现支持的最大对齐的对齐表示,其等于
。 §6.2.8 2_Alignof (max_align_t)
以下是候选 C99 解决方案。
// Form a prefix data type that can hold the `size` and preserves alignment.
// It is not specified which is type is wider, so use a union to allocate the widest.
#include <stddef.h>
union my2_size {
size_t size;
max_align_t a;
}
void *my2_alloc(size_t size) {
union my2_size *ptr = numa_alloc_local(sizeof *ptr + size);
if (ptr) {
ptr->size = size;
ptr++;
}
return ptr;
}
void my2_free(void *buf) {
if (buf) {
union my2_size *ptr = buf;
ptr--;
numa_free(ptr, sizeof *ptr + ptr->size);
}
}
// Return how many bytes are pointed to by a pointer allocated with my2_alloc()
size_t my2_size(void *buf) {
if (buf) {
union my2_size *ptr = buf;
ptr--;
return ptr->size;
}
return 0;
}
如果为单个值分配内存,您可能使用
sizeof()
来查找该值的类型所需的空间量。 您也应该知道该类型是什么,因为它是指针的类型。 因此,您只需对同一类型再次调用 sizeof()
即可。 (例如,如果您分配了 sizeof(Foo)
字节存储到 Foo*
中,那么您也想释放 sizeof(Foo)
字节。)
如果您为数组分配了内存,您应该已经跟踪该数组的长度,例如以便您知道迭代时在哪里停止。 将该长度乘以单个元素类型的大小。
指针仅指示内存中的一个不同点,这通常是数据开始的位置。开发商始终需要跟踪该位置有多少可用空间。 (
free
是该规则的一个例外)。
这是一个古老的问题,但它似乎位于“附加到指针的内存大小”之类的搜索结果的顶部,所以请允许我给出一个现代的答案。
似乎没有关于如何执行此操作的统一 API,但我可以提供 MSVS 和 gcc 的示例。
对于 Windows/MSVS,调用是
_msize(ptr)
:
void* data = malloc(5);
printf("%llu", _msize(data));
应该给你
5
在 gcc 中,调用是
malloc_usable_size(ptr)
:
#include <malloc.h>
void* data = malloc(5);
printf("%llu", malloc_usable_size(data));
应该给你
8
,或者可能是16
,或者可能完全是别的东西。 gcc 报告指针的完整填充大小,而不是您实际要求的大小,因此受最小大小、对齐方式等因素的影响。
希望这对现代寻求者有所帮助。 如果您是 Windows/Linux 可移植的,一个明显的事情就是定义一个有条件编译为正确调用的宏。