Memory management 调用free或delete是否会将内存释放回";系统“;

Memory management 调用free或delete是否会将内存释放回";系统“;,memory-management,Memory Management,我的问题是:调用free或delete是否会将内存释放回“系统”。我的意思是,系统是否减少了流程中的数据段 让我们考虑Linux上的内存分配器,即PTMaloC. 据我所知(如果我错了,请纠正我),ptmalloc维护一个内存块的空闲列表,当内存分配请求到来时,它会尝试从这个空闲列表分配一个内存块(我知道,分配器要复杂得多,但我只是简单地说),但是如果失败,它使用sbrk或brk系统调用从系统获取内存。当内存空闲时,该块被放入空闲列表中 现在考虑这个场景,在峰值负载上,堆上已经分配了很多对象。现

我的问题是:调用free或delete是否会将内存释放回“系统”。我的意思是,系统是否减少了流程中的数据段

让我们考虑Linux上的内存分配器,即PTMaloC.

据我所知(如果我错了,请纠正我),ptmalloc维护一个内存块的空闲列表,当内存分配请求到来时,它会尝试从这个空闲列表分配一个内存块(我知道,分配器要复杂得多,但我只是简单地说),但是如果失败,它使用sbrk或brk系统调用从系统获取内存。当内存空闲时,该块被放入空闲列表中

现在考虑这个场景,在峰值负载上,堆上已经分配了很多对象。现在,当载荷减小时,对象将自由移动。所以我的问题是:一旦对象是空闲的,分配器会做一些计算,以确定它是否应该将该对象保持在空闲列表中,或者根据空闲列表的当前大小,它可能会决定将该内存返回给系统,即使用sbrk或brk减少进程的数据段

glibc的文档告诉我,如果分配请求远远大于页面大小,那么将使用mmap进行分配,并在释放后直接释放回系统。酷。但假设我从未要求分配大于50字节的大小,我在系统的峰值负载上要求了很多这样的50字节对象。然后呢

据我所知(请纠正我),在进程结束之前,使用malloc分配的内存永远不会释放回系统,也就是说,如果我释放内存,分配器只会将其保留在空闲列表中。但困扰我的问题是,如果我使用工具查看进程的内存使用情况(我在Linux上使用的是pmap,你们使用的是什么?),它应该始终显示峰值负载时使用的内存(因为除非使用mmap分配内存,否则内存永远不会返回给系统)?也就是说,进程使用的内存永远不会减少(堆栈内存除外)?是吗

我知道我遗漏了一些东西,所以请解释一下这一切


专家们,请澄清我的观点。我将不胜感激。我希望我能够解释我的问题。

这完全取决于实现。在Windows VC++上,如果相应的内存页只包含空闲块,则程序可以将内存返回到系统。

我认为您已经掌握了回答自己问题所需的所有信息。pmap显示进程当前正在使用的内存。因此,如果在进程达到峰值内存之前调用pmap,则不会显示峰值内存。如果在进程退出之前调用pmap,则它将显示不使用mmap的进程的峰值内存。如果进程使用mmap,那么如果在使用最大内存的点调用pmap,它将显示内存使用的峰值,但这一点可能不在进程的末尾(它可能发生在任何地方)


这仅适用于您当前的系统(即基于您免费提供的文档以及mmap和malloc),但正如前面的海报所述,这些系统的行为取决于实现。

这在不同的实现中有所不同

把你的内存想象成一个巨大的长块,当你分配给它时,你会从内存中取出一点(下面标记为“1”):

如果我使用malloc分配更多内存,它会从系统中获得一些:

1112222
如果我现在释放“1”:

___2222
它不会返回到系统,因为它前面有两个(并且内存是作为一个连续块提供的)。但是,如果内存的末尾被释放,那么该内存将返回到系统。如果我释放了“2”而不是“1”。我会得到:

111
“2”所在的位将返回到系统。 释放内存的主要好处是可以重新分配该位,而不是从系统获得更多内存。e、 g:

33_2222
以下是不将内存释放回系统的一些“优势”:

1112222
  • 由于已经使用了大量内存,您很可能会再次这样做,并且
    • 当你释放内存时,操作系统需要做大量的文书工作
    • 当您再次需要它时,内存分配器必须重新初始化它刚接收到的区域中的所有数据结构
  • 释放的不需要的内存会被分页到磁盘上,而在磁盘上它实际上并没有多大区别
  • 通常,即使您释放了90%的内存,碎片化也意味着实际上可以释放的页面很少,因此查找空页面所需的努力并没有花得太多

我相信glibc中的内存分配器可以将内存返回到系统,但是否返回取决于您的内存分配模式

假设你做了这样的事情:

void *pointers[10000];
for(i = 0; i < 10000; i++)
    pointers[i] = malloc(1024);
for(i = 0; i < 9999; i++)
    free(pointers[i]);
void*指针[10000];
对于(i=0;i<10000;i++)
指针[i]=malloc(1024);
对于(i=0;i<9999;i++)
自由(指针[i]);
堆中唯一可以安全返回到系统的部分是堆末尾的“荒野块”。这可以使用另一个sbrk系统调用返回到系统,当最后一个块的大小超过某个阈值时,glibc内存分配器将执行此操作

上述计划将提供10000笔小额拨款,但只免费提供其中的前9999笔。最后一个应该(假设没有其他东西调用malloc,这是不可能的)位于堆的末尾。这将阻止分配器向系统返回任何内存

如果要释放剩余的分配,glibc的malloc实现应该能够将分配的大部分页面返回给系统

如果您正在分配和释放小块内存,其中一些是lon