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

标签 c++ windows winapi memory stack

我在 windows vista 及更高版本中遇到了一个奇怪的问题。当我使用具有大堆栈的 IFileOpenDialog 时,显示对话框后剩余的内存量下降了大约 1 GB。

#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 资源管理器中的 shell 扩展也会通过文件打开对话框加载。这就是您如何能够在该对话框中右键单击一个文件并获得所有那些非标准的好东西。但是,这意味着作为这些扩展的基础的 dll 正在加载到您的进程中。

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

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

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

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

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

关于c++ - Windows Vista+ IFileOpenDialog 和大堆栈的内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3517068/

相关文章:

c++ - 混合使用 C++ 和程序集无法将多个参数从 C++ 函数传递给程序集

c++ - 有没有办法专门针对目标原语模板?

c# - 如何确定 Windows 标识对应的是本地用户还是域用户?

python - 在 Windows 上调整 Python 控制台窗口大小的问题

c# - Windows 10应用-物联网系统管理能力

c# - 如何使用提供的凭据调用 SSPI 的 'AcquireCredentialsHandle'?

c++ - 我可以使用 VS2008 的 C++ 编译器使用 VS2010 并且仅使用 Server 2008 Platform SDK 进行编译吗?

c++ - IsWindows10OrGreater() 在 Windows 10 上失败

winapi - 调优套接字连接调用超时

c++ - 在 Qt6 中移植 QRegExp::exactMatch()