代码之家  ›  专栏  ›  技术社区  ›  zmbush

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

  •  1
  • zmbush  · 技术社区  · 16 年前

    #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
    

    更新2:

    几个月后我又回到这个问题上来了。我将主代码移到另一个函数,并将其作为具有指定堆栈大小的线程启动。编译时不需要堆栈大小。

    int main(){
      CreateThread(NULL, 100000000, analyze, NULL, 0, NULL);
      // Wait for analyze thread. 
    }
    
    int analyze(int ignore){
      // Do stuff
    }
    
    1 回复  |  直到 15 年前
        1
  •  1
  •   TheUndeadFish    16 年前

    我不知道你的剧本里到底发生了什么。但我以前见过文件打开对话框导致其他内存问题。

    当这个对话框被调用时,很多东西可能会被加载到您的进程中。特别是,出现在Windows资源管理器中的shell扩展也会随“文件打开”对话框一起加载。这样你就可以在对话框中右键点击一个文件,得到所有的非标准商品。但是,这意味着这些扩展的DLL正在加载到您的进程中。

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

    我知道这件轶事与你所做的事情没有直接关系,因为你分配了很多小的数量而不是一个大的数量。(在我的场景中,并没有使用malloc。我认为这是类似VirtualAlloc之类的东西。)但我猜大概也会发生类似的事情。

    “文件打开”对话框可能正在将某些内容加载到进程中,从而在malloc通常使用的空间中插入了一个屏障。但不知何故,这只发生在您使用大堆栈大小时,因为我猜,为堆栈保留的额外99MB空间以某种方式重新排列了地址空间的其余部分,从而容易出现此问题。

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