2010-08-18 72 views
1

我在Windows Vista及以上版本中遇到过一个奇怪的问题。当我用大堆栈使用IFileOpenDialog时,显示对话框后剩余的内存量下降了大约1 GB。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 
} 
+0

为什么要将堆栈大小设置为100 MB?对话框COM对象是否有可能产生自己的工作线程,这也可以获得100 MB的堆栈?尝试在使用Process Explorer或VMMap之前和之后查看它。 – Luke 2010-08-18 23:35:34

+0

这就是发生了什么,我如何让所有的线程都达到100MB? – zmbush 2010-08-19 00:07:05

+0

我不认为你可以。如果调用者未明确指定堆栈大小(这很少完成),则CreateThread使用链接器在可执行文件中指定的堆栈大小。我能想到的唯一的事情就是使用默认值并产生自己的线程来指定所需的堆栈大小。 – Luke 2010-08-19 03:16:23

回答

1

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

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

根据经验,我发现一旦文件打开对话框关闭,其中的一些DLL就不会被卸载。相反,他们保持现状,占用你的流程的一些地址空间。 (也许这是这些dll中的某种bug,或者可能是某种“优化”,以便在再次使用文件打开对话框的情况下使它们保持加载状态。)

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

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

文件打开对话框可能会在您的进程中加载​​某种东西,以某种方式将障碍插入malloc通常使用的空间中。但不知何故,只有当你使用这么大的堆栈大小时,才会发生这种情况,因为我猜想为堆栈预留的额外99MB空间会以某种方式重新排列其余的地址空间,使其易受此问题影响。

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

+0

我将把你的标记作为答案,VMMap帮助我诊断问题。 (IFileOpenDialog打开了11个线程,每个线程都有100MB的堆栈) – zmbush 2010-08-20 16:43:55