In C programming, you can pass any kind of pointer you like as an argument to free, how does it know the size of the allocated memory to free? Whenever I pass a pointer to some function, I have to also pass the size (ie an array of 10 elements needs to receive 10 as a parameter to know the size of the array), but I do not have to pass the size to the free function. Why not, and can I use this same technique in my own functions to save me from needing to cart around the extra variable of the array's length?
当前回答
当您调用malloc时,堆管理器将属于已分配块的内存量存储在某处。
我从来没有实现一个自己,但我猜在前面的内存分配块可能包含元信息。
其他回答
当您调用malloc时,堆管理器将属于已分配块的内存量存储在某处。
我从来没有实现一个自己,但我猜在前面的内存分配块可能包含元信息。
大多数C内存分配函数的实现都将为每个块存储记帐信息,或者内联存储,或者单独存储。
一种典型的方法(内嵌)是实际分配头部和您要求的内存,填充到某个最小大小。例如,如果你需要20个字节,系统可能会分配一个48字节的块:
包含大小、特殊标记、校验和、指向下一个/上一个块的指针等的16字节报头。 32字节的数据区(你的20字节填充为16的倍数)。
然后给您的地址就是数据区域的地址。然后,当你释放区块时,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的速度(释放时不需要合并相邻的块),这在我们工作的环境中特别重要。
来自comp.lang.c常见问题列表:free如何知道释放多少字节?
malloc/free实现在分配每个块时记住它的大小,因此在释放时不需要提醒它大小。(通常,大小存储在已分配块的相邻位置,这就是为什么如果已分配块的边界稍有超出,情况通常会很糟糕)
要回答第二个问题,是的,您可以(某种程度上)使用与malloc()相同的技术 通过简单地将每个数组中的第一个单元格分配给数组的大小。 这样就可以在不发送额外size参数的情况下发送数组。
与此相关的是,GLib库具有不保存隐式大小的内存分配函数——然后您只需将size参数传递给free即可。这可以减少部分开销。