C 当free()从堆中释放块时会发生什么?

C 当free()从堆中释放块时会发生什么?,c,memory,memory-management,malloc,heap,C,Memory,Memory Management,Malloc,Heap,因此,我在堆中分配了256个块: char* ptr1 = malloc(128); char* ptr2 = malloc(128); 现在,在释放ptr2(我假设它当前位于堆的顶部)之后,程序中断(堆的当前位置)不会减少。但是,如果我执行另一个malloc,则malloc返回的地址与释放的地址相同 因此,我有以下问题: 当我释放一个块时,程序中断为什么没有减少? 当我调用free时,到底发生了什么?它如何跟踪释放的内存,以便下次我声明malloc时,地址是相同的 当我释放一个块时,程序中断

因此,我在堆中分配了256个块:

char* ptr1 = malloc(128);
char* ptr2 = malloc(128);
现在,在释放ptr2(我假设它当前位于堆的顶部)之后,程序中断(堆的当前位置)不会减少。但是,如果我执行另一个malloc,则malloc返回的地址与释放的地址相同

因此,我有以下问题:

当我释放一个块时,程序中断为什么没有减少? 当我调用free时,到底发生了什么?它如何跟踪释放的内存,以便下次我声明malloc时,地址是相同的

当我释放一个块时,程序中断为什么没有减少

我相信它不会减少,因为内存已经给了程序

当我调用
free()
时,到底发生了什么

内存的这一部分被标记为可分配,它以前的内容可以被覆盖

考虑一下这个例子

[allocatedStatus][sideOfAllocation][allocatedMemory]
                                   ^-- Returned pointer
考虑到这一点,
free()
然后可以将
[allocatedStatus]
标记为false,以便堆上的未来分配可以使用该内存

它如何跟踪
free()
d内存,以便下次我声明
malloc()
地址相同吗


我想没有。它只是扫描了一些空闲内存,发现了之前标记为空闲的块。

我相信这完全取决于操作系统,一旦调用free(),它可能会选择立即回收内存,或者不在意,只是将该内存段标记为以后可能的获取(可能是同样的事情)。据我所知,在windows上的free()之后,任务管理器中会显示可用内存(如果重要)

请记住,我们在这里讨论的内存是虚拟的。因此,这意味着操作系统可以告诉您它想要的任何东西,并且可能不是机器物理状态的准确表示

想想你将如何管理内存分配如果你正在写一个操作系统,你可能不想做任何可能浪费资源的草率事情。我们这里讨论的是128字节,您是否想浪费宝贵的处理时间来单独处理它?这可能是这种行为的原因,至少是合理的。
在一个循环中执行,然后在另一个循环中释放(),或者只分配大块内存,看看会发生什么,然后进行实验。

下面是内存分配器工作原理的大致介绍:

您有一个分配器,它有一堆“存储箱”(“空闲列表”),它们只是空闲内存块的链接列表。每个bin都有一个与之关联的不同的块大小(即:您可以有一个8字节块、16字节块、32字节块等的列表,甚至是7或10字节块等任意大小的列表)。当您的程序请求内存时(通常通过malloc()),分配器将转到适合您的数据的最小存储箱,并检查其中是否有可用内存块。如果没有,那么它将从操作系统(通常称为页面)请求一些内存,并将它得到的块切割回一堆较小的块,以填充存储箱。然后它将这些空闲块中的一个返回到您的程序

当您调用free时,分配器会将该内存地址放回它来自的bin(也称为free list)中,每个人都很高兴。:)

内存仍然可以使用,因此您不必保留分页内存,但对于您的程序来说,它是免费的。

这篇GNU libc文章可能会有所帮助

这里是要点

有时,free实际上可以将内存返回到操作系统 并使过程更小。通常,它所能做的就是允许一个更晚的时间 调用malloc以重用空间。与此同时,空间仍然存在 作为malloc内部使用的免费列表的一部分在您的程序中


这是未指明的行为。您不能依赖于任何单一的答案,除非您只关心一个特定的平台/os/compiler/libc组合。您没有指定操作系统,C标准也没有描述或要求任何特定的实现。从C99开始(我还没有C11的最终发布版本):

7.20.3

连续调用所分配的存储的顺序和连续性 未指定calloc、malloc和realloc函数。指针 如果分配成功,则返回适当对齐,以便 指定给指向任何类型对象的指针,然后用于访问 在分配的空间中这样一个对象或这样一组对象 (直到空间被明确释放)。一个人的一生 已分配对象从分配扩展到解除分配。 每一个这样的分配都应该产生一个指向一个与之不相交的对象的指针 任何其他物体。指针返回指向起点(最低点)的点 已分配空间的字节地址)。如果该空间无法 如果已分配,则返回空指针。如果空间的大小 请求为零,行为由实现定义:或 返回null指针,或者行为就像大小为 非零值,但返回的指针不能用于 访问一个对象