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

时间:2013-03-22 02:15:24

标签: c memory memory-management malloc heap

所以我在堆中分配了256个块:

char* ptr1 = malloc(128);
char* ptr2 = malloc(128);

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

所以我有以下问题:

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

5 个答案:

答案 0 :(得分:4)

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

7.20.3

  

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

答案 1 :(得分:2)

这个manual的GNU libc可能会有所帮助。

这是要点

  

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

答案 2 :(得分:0)

  

当我释放一个块时,为什么程序不会中断?

我相信它不会减少,因为已经为该程序提供了内存。

  

当我致电free()时究竟发生了什么?

该部分内存被标记为可分配,其先前的内容可以被覆盖。

考虑这个例子......

[allocatedStatus][sideOfAllocation][allocatedMemory]
                                   ^-- Returned pointer

考虑到这一点,free()可以将[allocatedStatus]标记为false,因此堆上的未来分配可以使用该内存。

  

如何跟踪free() d内存,以便下次我声明   malloc()地址是一样的吗?

我不认为这样。它只是扫描了一些空闲内存,发现之前被标记为空闲的块。

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

以下是内存分配器的工作原理:

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

当你自由呼叫时,分配器获取该内存地址并将其放回到它所来自的bin(也就是空闲列表)中,并且每个人都很高兴。 :)

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