Windows Vista + проблема памяти с IFileOpenDialog и большим стеком - PullRequest
1 голос
/ 19 августа 2010

Я столкнулся со странной проблемой в 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), и когда я открываю диалоговое окно, запускается несколько потоков, каждый из которых имеет около 100 МБ. Есть ли способ сделать основной поток большим стеком, не предоставляя дочерним потокам по 100 МБ каждый?

Обновление 2:

Я вернулся к этой проблеме снова через несколько месяцев. Я переместил основной код в другую функцию и запустил его как поток с указанным размером стека. Нет необходимости в размере стека при компиляции.

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

int analyze(int ignore){
  // Do stuff
}

1 Ответ

1 голос
/ 19 августа 2010

Я не знаю точно, что происходит в вашем сценарии. Но раньше я видел, как диалог открытия файла вызывал другие проблемы с памятью.

Когда этот диалог вызывается, в ваш процесс может загружаться множество вещей. В частности, расширения оболочки, которые появляются в проводнике Windows, также загружаются с помощью диалога открытия файла. Вот как вы можете щелкнуть правой кнопкой мыши файл в этом диалоговом окне и получить все эти нестандартные вкусности. Однако это означает, что библиотеки dll, лежащие в основе этих расширений, загружаются в ваш процесс.

Из опыта я видел, что некоторые из этих библиотек не выгружаются после закрытия диалога открытия файла. Вместо этого они остаются присутствующими, занимая часть адресного пространства вашего процесса. (Может быть, это какая-то ошибка со стороны этих библиотек, или, может быть, это какая-то «оптимизация» для сохранения их загрузки в случае повторного использования диалога открытия файла.)

Следствием этого, с которым я имел дело, было то, что это повлияло на успешное выделение 1 ГБ памяти. Перед открытием диалога было доступно большое пространство адресного пространства, и выделение 1 ГБ могло быть успешным. Однако после открытия диалогового окна пара dll расширения оболочки приземлились прямо в середине доступного адресного пространства и разделили его на куски размером менее 1 ГБ, что привело к сбою выделения.

Я знаю, что этот анекдот не имеет прямого отношения к тому, что вы делаете, поскольку вы выделяете много небольших сумм вместо одной большой суммы. (И в моем сценарии это был не malloc. Я думаю, что это было что-то вроде VirtualAlloc или что-то подобное.) Но я бы предположил, что может происходить что-то похожее.

Диалог открытия файла может загружать что-то в ваш процесс, что каким-то образом вставляет барьер в пространство, которое обычно использует malloc. Но почему-то это происходит только тогда, когда вы используете этот большой размер стека, потому что я предполагаю, что дополнительные 99 МБ пространства, зарезервированного для стека, каким-то образом перестраивают оставшуюся часть адресного пространства, чтобы восприимчиво к этой проблеме.

Когда я исследовал собственную проблему, я использовал VMMap , чтобы сделать снимки адресного пространства моего процесса в различных точках, чтобы выяснить, что происходит. Возможно, вам повезет. Просто обратите внимание, что он смотрит на адресное пространство так, как его видит операционная система, а не так, как вы видите его внутри контекста определенного языка, такого как C ++. Так что не всегда легко выяснить, какая конкретная часть памяти используется malloc или любым другим механизмом распределения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...