所以我在堆中分配了256个块:
char* ptr1 = malloc(128);
char* ptr2 = malloc(128);
现在我释放ptr2,假设它当前位于堆的顶部,程序断点(堆的当前位置)不会减少。但是,如果我进行另一个malloc,则malloc返回的地址与已释放的地址相同。
所以我有以下问题:
当我释放一个块时,为什么程序断点不会减少? 调用free时发生了什么?它如何跟踪已释放的内存以便下一次声明malloc时地址相同?
所以我在堆中分配了256个块:
char* ptr1 = malloc(128);
char* ptr2 = malloc(128);
这个GNU libc手册可能会对你有所帮助。
以下是要点:
有时,free实际上可以将内存返回给操作系统并使进程变小。通常情况下,它只能允许稍后调用malloc来重用该空间。同时,该空间仍然作为malloc内部使用的空闲列表的一部分留存在程序中。
我认为一旦你调用free(),就完全取决于操作系统,它可能会立即回收该内存,也可能不关心并将该内存段标记为以后可能获取的内存(很可能是同样的事情)。据我所知,在Windows上,如果该内存(如果很大)在free()之后立即显示在任务管理器中。
请记住,我们在这里谈论的内存是虚拟的。因此,操作系统可以告诉您任何它想要的内容,并且可能不是机器物理状态的准确表示。
想想如果你正在编写一个操作系统,你会如何管理内存分配,你可能不想做任何可能浪费资源的仓促行动。我们在这里谈论的是128字节,你会想要浪费宝贵的处理时间来单独处理它吗?这可能是该行为的原因,也可能不是,至少是合理的。在循环中执行它,然后在另一个循环中释放它,或者只分配大块内存,看看会发生什么,进行实验。
这里大致介绍一下内存分配器的工作原理:
你有一个内存分配器,它有一堆“箱子”(“空闲列表”),这些箱子只是空闲内存块的链接列表。每个箱子都与不同的块大小相关联(例如:你可以为8字节块、16字节块、32字节块等设置列表...甚至为7或10字节块设置任意大小)。当你的程序请求内存(通常通过malloc())时,分配器会访问能够容纳你的数据的最小箱子,并检查其中是否有任何空闲内存块。如果没有,那么它将从操作系统中请求一些内存(通常称为页面),并将返回的块切成多个较小的块以填满该箱子。然后它将返回其中一个空闲块给你的程序。
当你调用free()时,分配器会将该内存地址放回到它来自的箱子(也称为空闲列表)中,所有人都很高兴。 :)
内存仍然可供使用,因此您不必不停地分页内存,但对于您的程序来说,它是空闲的。
free()
时,会发生什么?
该段内存被标记为可分配,其先前的内容可以被覆盖。[allocatedStatus][sideOfAllocation][allocatedMemory]
^-- Returned pointer
free()
可以将 [allocatedStatus]
标记为false,这样堆上的未来分配就可以使用该内存。
它如何跟踪
free()
的内存,以便下次我声明时malloc()
地址相同?
我认为它不会这样做。它只是扫描一些可用内存,然后找到之前标记为可用的块。