确定有关malloc的一些答案已经发布。
更加有趣的部分是自由的工作方式(在这个方向上,也可以更好地理解malloc)。
在许多malloc / free实现中,free通常不会将内存返回给操作系统(或至少仅在极少数情况下)。原因是您将在堆中留下间隙,因此可能会发生,您只需用间隙完成2或4 GB的虚拟内存即可。应该避免这种情况,因为一旦虚拟内存完成,您就会遇到很大的麻烦。另一个原因是,操作系统只能处理具有特定大小和对齐方式的内存块。具体来说:通常,操作系统只能处理虚拟内存管理器可以处理的块(通常是512字节的倍数,例如4KB)。
因此,将40字节返回给操作系统将不起作用。那么免费做什么?
Free将把内存块放在其自己的空闲块列表中。通常,它还会尝试将地址空间中的相邻块融合在一起。空闲块列表只是一个存储块的循环列表,这些存储块的开头具有一些管理数据。这也是为什么使用标准malloc / free管理非常小的内存元素效率不高的原因。每个内存块都需要其他数据,而较小的内存块会发生更多碎片。
当需要新的内存块时,空闲列表也是malloc查找的第一位。在从操作系统调用新内存之前,将对其进行扫描。当发现一块大于所需内存的块时,它将分为两部分。一个返回给呼叫者,另一个返回到空闲列表。
此标准行为有许多不同的优化(例如,用于一小块内存)。但是,由于malloc和free必须如此通用,因此当替代方法不可用时,标准行为始终是后备。在处理空闲列表方面也有一些优化,例如,将块存储在按大小排序的列表中。但是所有优化也都有其自身的局限性。
为什么您的代码崩溃:
原因是,通过将9个字符(不要忘记尾随的空字节)写入大小为4个字符的区域中,您可能会覆盖存储在另一块“数据”后面的另一块内存的管理数据(因为此数据最常存储在内存块的“前面”。当空闲时,然后尝试将您的块放入空闲列表中,它可以触摸此管理数据,因此偶然发现了被覆盖的指针。这将使系统崩溃。
这是一个相当优雅的行为。我还看到过这样的情况,即某个地方的失控指针已覆盖了无内存列表中的数据,并且系统并没有立即崩溃,而是在以后出现了一些子例程。即使在中等复杂度的系统中,此类问题也确实非常难以调试!在我参与的一个案例中,我们(一大批开发人员)花了几天的时间来找出崩溃的原因-因为它的位置与内存转储指示的位置完全不同。就像定时炸弹一样。您知道,您的下一个“免费”或“ malloc”将崩溃,但您不知道为什么!
这些是一些最严重的C / C ++问题,也是指针如此有问题的原因之一。