强制释放内存到操作系统

Force memory release to the OS

本文关键字:操作系统 内存 释放      更新时间:2023-10-16

我有一个应用程序,需要大约20 MB的内存。在一个很少使用的算法中,它(std::vector)临时分配250 MB。在释放后,系统监视器仍然显示这种用法。如何将内存释放回系统?

你不能,也不应该。

虚拟内存分配是复杂的,不能通过简单地观察System Monitor中的数字来充分理解。它可能看起来好像一个进程使用了比它应该使用的更多的内存,但这只是虚拟内存寻址工作方式的产物。

请放心,如果您正确地释放了该内存,并且操作系统确实需要它,它将被重新分配。

这里唯一真正可行的点是停止使用系统监视器,好像它是一个准确的测量物理内存在使用你的进程!

使用mmap()或VirtualAlloc()来分配和释放内存。这将立即返回操作系统。

为了与std::vector一起使用,你需要为它提供一个std::allocator。您可能会发现,手工滚动自己的vector w/location和new和直接析构函数调用更容易。

通常系统堆分配器会为你正确处理这个;然而,看起来你发现了一个情况,他们没有。

这不是虚拟内存和堆管理器的工作方式(至少在Windows上不是)。

在Windows上,你有两个级别的内存管理。内存管理的最基本形式是由操作系统完成的。在操作系统中,您可以通过VirtualAlloc()请求内存。VirtualAlloc()粒度的倍数提供内存。粒度的典型值是64 kB。

正确理解:如果您从VirtualAlloc()请求1字节,您可以这样做。但是:你会浪费很多内存,因为函数返回的块至少有64 kB。

你可能会问:"WTF?为什么?"。想象一下,操作系统将能够跟踪您分配的每个字节。存储分配的每个字节的地址将需要比实际可用内存更多的内存。所以必须有一个妥协。

这就是为什么Windows有另一个机制:Windows堆管理器。Windows堆管理器占用64 kB的大块虚拟内存(通过VirtualAlloc(),同样的调用),然后为您做一些聪明的管理。

如果你从Windows堆管理器请求1个字节,你得到一个指向1个可用字节的指针。在那个内存位置周围会有一些开销,对此我不想深入讨论。这将需要解释术语堆,段,块,预分配元数据和后分配元数据。你可以在Mark Russinovich的《Windows内部》一书中了解到所有这些。

可以这样考虑:堆管理器将进一步将64kb块分解为不同大小的分配区域。在这个64kb块的某个地方,它将存储如何使用内存的信息。

如果您free()delete一个或几个指针,这些内存很可能仍然没有释放。a)它仍然包含Windows堆管理器的管理结构,b)它可能包含至少一个指针。

因此,即使该内存区域中只剩下1个指向1字节的指针,Windows堆管理器也无法将64kb的块返回给操作系统。

其他需要考虑的事情(但我不确定):Windows堆管理器可能不会在每个free()delete检查64 kB块的所有内存是否被释放。a)计算可能会花费很长时间(特别是对于像c++这样的语言),b)在不久的将来,无论如何,您可能会将malloc()new作为一个字节。那么,堆管理器为什么要将它已经拥有的内存返回给操作系统呢?

以上所有内容都独立于分页进程。未使用的内存可以按页大小的块进行分页,通常为4 kB。"页面out"

表示"写入磁盘到pagefile.sys"。

为什么这很重要?这意味着虚拟内存不必使用快速而有价值的物理RAM。

你释放了250mb ?让操作系统决定它是否可以在物理RAM中保留这250 MB,或者是否将其分页。如果您的应用程序请求新的虚拟内存,它可能会受益于这个事实,即它恰好是免费的(即不调用VirtualAlloc())。