2010-12-21 30 views
5

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

这里有几个例子,从的VMMap:http://www.flickr.com/photos/[email protected]/5280550393/

什么人会分配内存这样的块,其中它更是保留但未提交?我的过程有30堆是否合理?谢谢。

+0

我不认为在一次两个地方发布完全相同的问题并不是很好。 http://forum.sysinternals.com/uncommitted-reserved-memory-in-my-process_topic24690.html – wj32 2010-12-21 21:29:10

+8

我认为这很好。 Sysinternals是VMMap工具的作者,因此他们可能知道他们的工具为什么要报告这些信息。 StackOverflow上的人们可能知道哪些代码会以这种模式分配内存。两个不同的受众可能不会阅读这两个论坛。 – Art 2011-01-04 19:18:59

回答

7

我想通了 - 它是通过调用malloc分配的CRT堆。如果使用malloc分配一大块内存(例如,2 MB),它将分配一个确定的内存块。但是,如果你分配较小的块(比如说177kb),那么它将保留1MB的内存块,但只能提交大约你所要求的内容(例如,对于我的177kb请求,这是184kb)。当释放该小块时,较大的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不会将内存返回到操作系统,除了重新启动我的进程或编写我自己的内存管理器外,我还没有找到任何解决此问题的方法。

0

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

只有真正触摸的代码才会被分页。如果我正确理解术语,那就是它的提交时间。

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

0

每当在应用程序中创建一个线程时,线程调用堆栈的地址空间中将保留一定的(可配置的)内存量。除非你的线程真的需要所有的内存,否则不需要提交所有保留的内存。所以只有一部分需要承诺。

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

实际的考虑是保留内存是堆栈大小的硬限制,这会减少应用程序可用的地址空间。但是,只需提交一部分备用数据,我们就不必从系统中消耗相同数量的内存直到需要为止。

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

相关问题