我的进程中所有这些未提交的保留内存是啥?

Posted

技术标签:

【中文标题】我的进程中所有这些未提交的保留内存是啥?【英文标题】:What's all this uncommitted, reserved memory in my process?我的进程中所有这些未提交的保留内存是什么? 【发布时间】:2011-05-29 01:05:15 【问题描述】:

我正在使用 SysInternals 的 VMMap 来查看我的 Win32 C++ 进程在 WinXP 上分配的内存,我看到了一堆分配,其中部分分配的内存被保留但未提交。据我所知,根据我的阅读和测试,C++ 程序中使用的所有常见内存分配器(例如 malloc、new、LocalAlloc、GlobalAlloc)总是分配完全提交的内存块。 堆是保留内存但在需要时才提交的代码的常见示例。我怀疑其中一些块是 Windows/CRT 堆,但这些类型的块似乎比我预期的堆要多。我在进程中看到大约 30 个这些块,大小在 64k 到 8MB 之间,并且我知道我的代码从未故意调用 VirtualAlloc 来分配保留的、未提交的内存。

以下是 VMMap 中的几个示例:http://www.flickr.com/photos/95123032@N00/5280550393/

还有什么会分配这样的内存块,其中大部分是保留但未提交的?我的进程有 30 个堆有意义吗?谢谢。

【问题讨论】:

我认为同时在两个地方发布完全相同的问题并不是一件好事。 forum.sysinternals.com/… 我觉得完全没问题。 Sysinternals 是 VMMap 工具的作者,所以他们可能知道他们的工具为什么会报告此类信息。 *** 上的人可能知道哪些代码会以这种模式分配内存。两个不同的受众可能不会同时阅读这两个论坛。 【参考方案1】:

我想通了 - 这是通过调用 malloc 分配的 CRT 堆。如果您使用 malloc 分配一大块内存(例如 2 MB),它会分配一个已提交的内存块。但是,如果您分配较小的块(例如 177kb),那么它将保留 1 MB 的内存块,但只提交大约您要求的内容(例如,184kb 用于我的 177kb 请求)。

当您释放那个小块时,较大的 1 MB 块不会返回给操作系统。除 4k 之外的所有内容均未提交,但仍保留完整的 1 MB。如果您随后再次调用malloc,它将尝试使用该 1 MB 块来满足您的请求。如果它无法满足您对已保留内存的请求,它将分配一个新的内存块,该内存块是先前分配的两倍(在我的情况下,它从 1 MB 变为 2 MB)。我不确定这种翻倍模式是否会持续下去。

要真正将释放的内存返回给操作系统,您可以调用_heapmin。我认为这将使未来的大型分配更有可能成功,但这一切都取决于内存碎片,如果分配失败(?),也许 heapmin 已经被调用,我不确定。由于 heapmin 会释放内存(需要时间),因此也会对性能造成影响,然后 malloc 需要在再次需要时从操作系统重新分配它。此信息适用于 Windows/32 XP,您的里程可能会有所不同。

更新:在我的测试中,heapmin 完全没有做任何事情。而 malloc 堆只用于小于 512kb 的块。即使 malloc 堆中有 MB 的连续可用空间,它也不会将其用于超过 512kb 的请求。就我而言,这个已释放、未使用但保留的 malloc 内存占用了我进程的 2GB 地址空间的很大一部分,最终导致内存分配失败。而且由于 heapmin 不会将内存返回给操作系统,所以除了重新启动进程或编写自己的内存管理器之外,我还没有找到任何解决此问题的方法。

【讨论】:

【参考方案2】:

每当在您的应用程序中创建线程时,都会在地址空间中为线程的调用堆栈保留一定的(可配置的)内存量。除非您的线程实际上需要所有这些内存,否则无需提交所有保留的内存。所以只需要提交一部分。

如果需要超过承诺的内存量,则可以获得更多的系统内存。

实际考虑是,保留内存是对堆栈大小的硬限制,它会减少应用程序可用的地址空间。但是,通过只提交一部分保留,我们不必在需要时从系统消耗相同数量的内存。

因此,每个线程都有可能拥有一部分保留的未提交内存。我不确定在这些情况下页面类型是什么。

【讨论】:

那么这是否意味着每当应用程序创建例如 10 个线程时,操作系统会提前为每个线程“保留”一些内存 (~4KB) 以供线程将来使用?【参考方案3】:

它们可能是加载到您的进程中的 DLL 吗? DLL(和可执行文件)是映射到进程地址空间的内存。我相信这最初只是保留空间。该空间由文件本身(至少在最初)而不是页面文件支持。

只有实际触及的代码才会被分页。如果我理解正确的术语,那就是提交的时候。

您可以通过在调试器中运行您的应用程序并查看已加载的模块并将它们的位置和大小与您在 VMMap 中看到的内容进行比较来确认这一点。

【讨论】:

DLL 在 VMMap 中作为 IMAGE 或 MAPPED FILE 单独列出。这些分配显示为 PRIVATE 内存,因此它们不是 DLL。

以上是关于我的进程中所有这些未提交的保留内存是啥?的主要内容,如果未能解决你的问题,请参考以下文章

linux的活动进程中有个zombie是啥

内存保留和提交

转---队列堆栈堆栈的区别

操作系统学习笔记 windows内存管理

安卓Android的内存管理原理解析

Android进程分类与管理