Windows Vista +内存问题与IFileOpenDialog和大堆栈

我在Windows Vista及以上版本中遇到过一个奇怪的问题。 当我用大堆栈使用IFileOpenDialog时,显示对话框后剩余的内存量下降了大约一千兆字节。

#include <windows.h> #include <Shobjidl.h> #include <iostream> void memGrab(char *); int main(int argc, char **argv){ char Message[128]; CoInitialize(NULL); if(argc > 1){ wsprintf(Message, "Starting Memory Test: %c", argv[1][0]); std::cout << Message << "\n"; if(argv[1][0] == 'b') memGrab("before"); TCHAR *fileName = (TCHAR *)malloc(sizeof(TCHAR) * 1024); IFileOpenDialog *pfd; int index = 0; int len = 0; int i = 0; HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pfd)); if(SUCCEEDED(hr)){ pfd->Show(NULL); } pfd->Release(); if(argv[1][0] == 'a') memGrab("After"); } CoUninitialize(); } void memGrab(char *text){ for(int i = 0; i < 400000; i++){ if(!malloc(10240)){ char Message[128]; wsprintf(Message, "Memory Gone %s: %d K", text, i * 10); std::cout << Message << "\n"; exit(0); } } } 

当我编译这个程序时没有设置堆栈大小( cl testMem.cpp Shell32.lib Ole32.lib user32.lib )。 我得到以下结果:

 C:\RWSource>testMem.exe b Starting Memory Test: b Memory Gone before: 1984040 K C:\RWSource>testMem.exe a Starting Memory Test: a Memory Gone After: 1875640 K 

但是,当我编译它与设置堆栈大小( cl testMem.cpp Shell32.lib Ole32.lib user32.lib /F100000000 )。 我松了大量的可分配内存。

 C:\RWSource>testMem.exe b Starting Memory Test: b Memory Gone before: 1795370 K C:\RWSource>testMem.exe a Starting Memory Test: a Memory Gone After: 463840 K 

更新1:

我用VMMap检查内存(谢谢TheUndeadFish),当我打开对话框时,有多个线程开始都有大约100MB。 有没有办法让主线程有一个大的堆栈,而不是给每个线程100MB的儿童?

更新2:

几个月后我再次回到这个问题。 我把主代码移到了另一个函数中,并以一个具有指定堆栈大小的线程启动它。 编译时不需要堆栈大小。

 int main(){ CreateThread(NULL, 100000000, analyze, NULL, 0, NULL); // Wait for analyze thread. } int analyze(int ignore){ // Do stuff } 

我不知道你的情况到底发生了什么。 但是我看到文件打开对话框会导致其他内存麻烦。

当该对话框被调用时,很多事情可能会被加载到你的过程中。 特别是,在Windows资源管理器中出现的外壳扩展也被加载到文件打开对话框中。 这就是你能够右键单击对话框中的文件,并获得所有这些非标准的好东西。 但是,这意味着这些扩展的基础DLL正在加载到您的过程中。

从经验上看,一旦文件打开对话框关闭,其中的一些DLL就不会被卸载。 相反,他们保持现状,占用你的流程的一些地址空间。 (也许这是这些dll中的某种错误,或者可能是某种“优化”来保存它们,以防再次使用“文件打开对话框”)。

我处理的结果是影响了单个1GB内存分配的成功。 在打开对话框之前,有大量的地址空间可用,1GB分配可能成功。 然而,在打开对话框之后,一些shell扩展DLL正好落在可用地址空间的中间,并将其分成小于1GB的块,从而导致分配失败。

我知道这个轶事并不直接与你在做什么,因为你分配了很多小数额,而不是一个大数额。 (在我的情况下,它不是使用malloc,我认为这是像VirtualAlloc或类似的东西),但我猜想可能会发生类似的事情。

文件打开对话框可能会加载一些东西到你的进程,以某种方式插入一个屏障到malloc通常使用的空间。 但是不知何故,这只会在你使用这么大的堆栈大小的时候才会发生,因为我猜想为这个堆栈保留的额外的99MB的空间是以某种方式重新排列了其余的地址空间以便于处理这个问题。

当我调查自己的问题时,我使用VMMap在不同的地方拍摄了我的进程的地址空间的快照,以了解发生了什么事情。 你可能有这样的运气。 请注意,它看起来像操作系统看到的地址空间,而不是像从C ++的特定语言里面看到的那样。 因此,找出malloc或任何其他分配机制正在使用的内存的特定部分并不一定容易。