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

时间:2010-08-18 22:00:50

标签: c++ windows winapi memory stack

我在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
}

1 个答案:

答案 0 :(得分:1)

我不确切知道你的场景中发生了什么。但我之前看到文件打开对话框导致其他内存问题。

当调用该对话框时,很多东西可能会加载到您的进程中。特别是,Windows资源管理器中出现的shell扩展也会使用“文件打开”对话框加载。这就是你如何能够右键单击该对话框中的文件并获得所有那些非标准的好东西。但是,这意味着构成这些扩展的dll会被加载到您的进程中。

根据经验,我看到一些文件打开对话框关闭后,这些dll中的一些没有被卸载。相反,它们会保持存在,占用您流程的一些地址空间。 (也许这是那些dll的某种错误,或者可能是某种“优化”来保持它们的加载,以防再次使用文件打开对话框。)

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

我知道这个轶事与你正在做的事情没有直接关系,因为你分配了很多小额而不是一大笔金额。 (在我的场景中,并没有使用malloc。我认为它就像VirtualAlloc之类的东西。)但我猜可能会发生大致相似的事情。

文件打开对话框可能会在您的进程中加载​​一些内容,以某种方式在malloc通常使用的空间中插入一个屏障。但不知何故,只有当你使用那么大的堆栈大小时才会发生这种情况,因为我想为堆栈预留的额外99MB空间会以某种方式重新排列地址空间的其余部分以容易出现这个问题。

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