当使用free()函数释放堆上的内存块时会发生什么?

4

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

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

现在我释放ptr2,假设它当前位于堆的顶部,程序断点(堆的当前位置)不会减少。但是,如果我进行另一个malloc,则malloc返回的地址与已释放的地址相同。
所以我有以下问题:
当我释放一个块时,为什么程序断点不会减少? 调用free时发生了什么?它如何跟踪已释放的内存以便下一次声明malloc时地址相同?
5个回答

4
这是未指定的行为。除非您只关心一个特定的平台/操作系统/编译器/libc组合,否则不能依赖于任何单个答案。您没有指定操作系统,而C标准也没有描述或要求任何特定的实现。从C99开始(我还没有最终发布的C11版本):
7.20.3
连续调用calloc、malloc和realloc函数分配的存储空间的顺序和连续性是未指定的。如果分配成功,则返回的指针适当地对齐,以便将其分配给任何类型的对象的指针,然后用于访问分配的空间中的这种对象或这种对象的数组(直到显式释放空间)。分配的对象的生命周期从分配开始到释放为止。每次此类分配都应产生指向与任何其他对象不相交的对象的指针。返回的指针指向分配空间的起始位置(最低字节地址)。如果无法分配空间,则返回空指针。如果请求的空间大小为零,则行为是实现定义的:可能返回空指针,或者行为就像大小是某个非零值一样,但返回的指针不得用于访问对象。

2
这里是需要翻译的内容:

这个GNU libc手册可能会对你有所帮助。

以下是要点:

有时,free实际上可以将内存返回给操作系统并使进程变小。通常情况下,它只能允许稍后调用malloc来重用该空间。同时,该空间仍然作为malloc内部使用的空闲列表的一部分留存在程序中。


0

我认为一旦你调用free(),就完全取决于操作系统,它可能会立即回收该内存,也可能不关心并将该内存段标记为以后可能获取的内存(很可能是同样的事情)。据我所知,在Windows上,如果该内存(如果很大)在free()之后立即显示在任务管理器中。

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

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


0

这里大致介绍一下内存分配器的工作原理:

你有一个内存分配器,它有一堆“箱子”(“空闲列表”),这些箱子只是空闲内存块的链接列表。每个箱子都与不同的块大小相关联(例如:你可以为8字节块、16字节块、32字节块等设置列表...甚至为7或10字节块设置任意大小)。当你的程序请求内存(通常通过malloc())时,分配器会访问能够容纳你的数据的最小箱子,并检查其中是否有任何空闲内存块。如果没有,那么它将从操作系统中请求一些内存(通常称为页面),并将返回的块切成多个较小的块以填满该箱子。然后它将返回其中一个空闲块给你的程序。

当你调用free()时,分配器会将该内存地址放回到它来自的箱子(也称为空闲列表)中,所有人都很高兴。 :)

内存仍然可供使用,因此您不必不停地分页内存,但对于您的程序来说,它是空闲的。


0
当我释放一个块时,为什么程序中的断点值不会减少? 我认为这是因为那部分内存已经被分配给程序了。
当我调用 free()时,会发生什么? 该段内存被标记为可分配,其先前的内容可以被覆盖。
考虑下面的例子...
[allocatedStatus][sideOfAllocation][allocatedMemory]
                                   ^-- Returned pointer

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

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

我认为它不会这样做。它只是扫描一些可用内存,然后找到之前标记为可用的块。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接