malloc()和free()如何工作?

我想知道如何mallocfree工作。

int main() {
    unsigned char *p = (unsigned char*)malloc(4*sizeof(unsigned char));
    memset(p,0,4);
    strcpy((char*)p,"abcdabcd"); // **deliberately storing 8bytes**
    cout << p;
    free(p); // Obvious Crash, but I need how it works and why crash.
    cout << p;
    return 0;
}

如果答案在内存层面上是深入的,如果可能的话,我会很感激。


好的,关于malloc的一些答案已经发布。

更有趣的部分是自由作品 (在这个方向上,malloc也可以更好地理解)。

在许多malloc / free实现中,free一般不会将内存返回给操作系统(或者至少在极少数情况下)。 原因是你会在你的堆中留下空隙,因此可能会发生,你刚刚完成了2或4 GB的虚拟内存与空白。 这应该避免,因为一旦虚拟内存完成,你将会遇到非常大的麻烦。 另一个原因是,操作系统只能处理特定大小和对齐的内存块。 具体而言:通常操作系统只能处理虚拟内存管理器可以处理的块(最常见的是512字节的倍数,例如4KB)。

因此,返回40字节的操作系统将无法正常工作。 那么免费做什么?

自由将把内存块放在它自己的空闲块列表中。 通常它也会尝试将地址空间中的相邻块融合在一起。 空闲块列表只是一个内存块的循环列表,它在开始时有一些管理数据。 这也是为什么使用标准malloc / free管理非常小的内存元素效率不高的原因。 每个内存块都需要额外的数据,更小的尺寸会发生更多的碎片。

free-list也是malloc在需要一块新内存时的首要位置。 它在从OS调用新内存之前进行扫描。 当发现大于所需内存的块时,它被分成两部分。 一个返回给调用者,另一个退回到空闲列表中。

对这种标准行为有许多不同的优化(例如对于小块内存)。 但是由于malloc和free必须如此普遍,所以当替代品不可用时,标准行为始终是回退。 在处理自由列表时也有优化 - 例如将大块存储在按大小排序的列表中。 但是,所有优化也有其自身的局限性。

为什么你的代码崩溃了:

原因在于,通过将9个字符(不要忘记尾随空字节)放入一个大小为4个字符的区域,您可能会覆盖为位于数据块“后面”的另一块内存而存储的管理数据(因为这些数据通常存储在内存块的“前面”)。 当空闲时,然后尝试将你的块放入空闲列表中,它可以触摸这个管理数据,并因此碰到覆盖指针。 这会使系统崩溃。

这是一种相当优美的行为。 我还看到了一些情况,指向某处的失控指针覆盖了无内存列表中的数据,系统并未立即崩溃,而是稍后再执行一些子例程。 即使在一个中等复杂的系统中,这些问题真的很难调试! 在我涉及的一个案例中,我们(一大批开发人员)花了好几天的时间来找出崩溃的原因 - 因为它与内存转储指出的位置完全不同。 它就像一颗定时炸弹。 你知道,你的下一个“免费”或“malloc”会崩溃,但你不知道为什么!

这些是最糟糕的C / C ++问题,也是指针可能如此问题的一个原因。


正如aluser在这个论坛主题中所说:

你的进程有一个从地址x到地址y的内存区域,称为堆。 你所有的malloc'd数据都在这个区域。 malloc()保留一些数据结构,让我们说一个堆中空闲空间块的列表。 当你调用malloc的时候,它通过列表查找一个足够大的块,返回一个指向它的块,并记录它不再是空闲的以及它有多大的事实。 当你用相同的指针调用free()时,free()会查找该块的大小,并将其添加回空闲块()的列表中。 如果你调用malloc()并且它在堆中找不到足够大的块,它使用brk()系统调用来增加堆,即增加地址y并导致旧y和新y之间的所有地址成为有效的记忆。 brk()必须是系统调用; 没有办法从用户空间完全做同样的事情。

malloc()依赖于系统/编译器,因此很难给出具体的答案。 然而基本上它确实记录了它被分配的内存,并且取决于它如何执行,所以你的免费通话可能会失败或成功。

malloc() and free() don't work the same way on every O/S.


malloc / free的一个实现执行以下操作:

  • 通过sbrk()(Unix调用)从操作系统获取一块内存。
  • 在内存块周围创建一个标题和一个页脚,并提供一些信息,如大小,权限以及下一个和上一个块的位置。
  • 当对malloc的调用进来时,会引用一个指向适当大小的块的列表。
  • 然后返回该块,并相应地更新页眉和页脚。
  • 链接地址: http://www.djcxy.com/p/43901.html

    上一篇: How do malloc() and free() work?

    下一篇: Segmentation faulting in assignment