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个字节。使用一个非常简单的位掩码(即不在线)来决定是否分配了128字节块。
我开发的其他程序也有不同的池,用于16字节块、64字节块、256字节块和1K块,同样使用位掩码来决定所使用或可用的块。
这两个选项都设法减少了会计信息的开销,并提高了malloc
和free
(解放时不需要合并相邻的区块),特别是在我们工作的环境中。