如果一个进程最初在堆中分配了许多页面,但是页面中的许多数据已被释放,那么操作系统是否进行了某种优化以将数据合并为一个页面,因此可以释放其他页面?
答案 0 :(得分:2)
通常,什么也没有发生,堆中将继续有“洞”。
由于进程已知的(虚拟)内存地址必须保持有效,因此操作系统无法自行执行“堆压缩”。但是,某些运行时(如.Net)可以做到这一点。
如果您使用的是C或C ++,则默认情况下,您所希望的只是malloc()
将能够重用以前释放的块。但是,如果您的使用模式是“分配许多小对象,然后随机释放其中的一半”,则内存利用率可能不会从峰值下降太多。
答案 1 :(得分:1)
如果进程最初在堆中分配了许多页面
一个进程最初不会在堆中分配页面。
操作系统是否进行了某种优化以将数据合并到一个页面中,以便可以释放其他页面
操作系统不了解用户堆。它为该进程分配页面。该过程如何处理这些页面就可以了(即,将它们用于堆,堆栈,代码等)。
进程的堆管理器可以合并释放的内存块。发生这种情况时,通常可以解决堆碎片问题。但是,我从未见过分页系统上的堆管理器,一旦页面被操作系统映射,该堆管理器便不会对页面进行映射。
答案 2 :(得分:1)
进程的堆永远不会有漏洞。堆是分配给进程的数据段的一部分,基本上通过使用sbrk(2)
系统调用(将数据段固定为新的大小)动态地增长到堆栈段的顶部。堆是分配的页面的连续段(至少在虚拟地址空间方面)。 malloc(3)
永远不会将堆空间(或其一部分)返回给系统。有关此信息,请参见malloc(3)
。尽管有一些内存分配器允许一个进程拥有多个堆(通过分配新的内存段,通过使用mmap(2)
系统调用),但内存分配器分配的段通常永远不会返回到系统。
发生的事情是,内存分配器重用了sbrk(2)
和mmap(2)
分配的堆空间,并管理了要重用的内存,但是它永远不会返回给系统。
但是请不要担心,因为系统会以良好且有利可图的方式处理此问题。
这不会影响整个系统的管理,除了它消耗虚拟地址空间的事实外,如果您不使用它们,直到过程再次引用它们并使系统成为系统,页面内容可能会在交换设备中结束。从交换设备重新加载它们。如果您的进程没有重复使用它在堆中创建的漏洞,则最可能的目标是系统将它们移至交换设备,然后继续将其用于其他进程。
此刻,我不知道系统是否通过不交换掉零页面来优化交换分配,例如,它与可执行文件的文本段一样(它们从不进入交换设备,因为它们的内容是已经在可执行文件中被交换了-这就是您无法在古老的unices中擦除程序可执行文件的原因,或者是不再需要在常用程序中使用粘性位的原因- -),但我认为并非如此(原因是最不可能的是应用程序会将未使用的页面清零)
仅在系统中有15Gb单个进程的堆使用且大部分时间未使用90%堆使用的情况下才发出警告。但是最好在优化分配资源时考虑一下,因为在大多数情况下90%以上的时间未使用时,消耗15Gb堆的进程似乎是一个糟糕的设计。如果没有其他机会,只需为系统提供足够的交换空间即可。