malloc()
函数时,你需要指定分配内存的数量。实际使用的内存量略大于此值,并包含记录至少块大小的额外信息。你不能(可靠地)访问其他信息,也不应该这样做 :-)free()
函数时,它只需查看其他信息即可找出块的大小。malloc_size()
函数,可靠地从malloc()
分配的指针中获取块大小。但是,没有可靠、可移植的方法实现这一点。 - laaltofree()
要求程序员准确报告malloc()
块的大小会有多可怕吗?内存泄漏本来就已经够糟糕了。 - MusiGenesisC语言内存分配函数的大多数实现会为每个块存储记账信息,可以直接内联或单独存储。
一种典型的内联方式是实际上分配一个头部和你要求的内存,将其填充到某个最小大小。举个例子,如果你请求20字节,系统可能会分配一个48字节的块:
然后给你的地址是数据区域的地址。当你释放该块时,free
只需要获取你提供的地址,并假设你没有破坏该地址或周围的内存,则会检查它之前的记账信息。以图形方式表示就是这样:
____ The allocated block ____
/ \
+--------+--------------------+
| Header | Your data area ... |
+--------+--------------------+
^
|
+-- The address you are given
需要记住的是,头部和填充的大小完全由实现定义(实际上整个内存分配系统都是由实现定义的(a),但内联计算选项是常见的一种)。
内存分配信息中存在的校验和和特殊标记经常会导致错误,比如“内存区域已损坏”或“重复释放”,如果您覆盖它们或释放两次相同的内存。
填充(使分配更有效率)是为什么有时候您可以在请求的空间末尾写入一点内容而不会引起问题的原因(但是不要这样做,这是未定义行为,即使有时候有效,也不能这样做)。
(a)我曾在嵌入式系统中编写过malloc
的实现,在那里无论您要求多少,都只得到128字节(那是系统中最大结构体的大小),假设您请求的是128字节或更少(请求更多会返回NULL值)。一个非常简单的位掩码(即不是内联的)用于决定是否分配了128字节的块。
我开发的其他内存分配系统针对16字节块、64字节块、256字节块和1K字节块具有不同的内存池,同样使用位掩码来决定哪些块被使用或可用。
这两个选项都成功减少了内存分配信息的开销,并增加了malloc
和free
的速度(在释放时无需合并相邻的块),这在我们工作的环境中尤为重要。
malloc
的唯一真正要求是在成功的情况下为您提供至少与您请求的大小相同的内存块。单个块在访问其中的元素时是连续的,但并不要求这些块来自连续的区域。 - paxdiablovoid *x = malloc(200); free(x, 500);
不会有好结果 :-) 无论如何,为了效率,缓冲区的实际大小可能会更大(你不能依赖它)。 - paxdiablo来自comp.lang.c
的FAQ列表:free函数如何知道要释放的字节数?
malloc/free实现在分配内存块时记住每个块的大小,因此释放时不需要提供大小信息。(通常,大小信息存储在分配的内存块旁边,这也是为什么稍微超出分配内存块边界就会导致严重错误的原因)
free
上使用。也许答案不能令您满意,但我认为您不会得到更多通用适用的信息 :-) - jdehaanmalloc
,堆分配器存储了原始返回指针与free
释放内存所需的相关细节之间的映射关系。这通常涉及以分配器使用的任何形式存储内存区域的大小,例如原始大小、用于跟踪分配的二叉树中的节点或正在使用的内存“单元”的计数。如果您“重命名”指针或以任何方式复制它,则free
不会失败。但是,它不是引用计数的,只有第一个free
才是正确的。其他free
将是“双重释放”错误。尝试free
任何指向先前malloc
未释放的值不同的指针都是错误的。无法部分释放从malloc
返回的内存区域。malloc
时将属于分配块的内存量存储在某处。我从未亲自实现过,但我猜分配块前面的内存可能包含元信息。malloc()
和free()
是与系统/编译器有关的,因此很难给出具体答案。
更多信息请参见此其他问题。
typedef struct {
size_t numElements
int elements[1]; /* but enough space malloced for numElements at runtime */
} IntArray_t;
#define SIZE 10
IntArray_t* myArray = malloc(sizeof(intArray_t) + SIZE * sizeof(int));
myArray->numElements = SIZE;
malloc()
相同的技术,只需将每个数组内的第一个单元格分配给数组的大小即可。这样可以发送数组而无需发送额外的大小参数。