LoadLibrary() завершается с ошибкой 8 (ERROR_NOT_ENOUGH_MEMORY)

Позднее редактирование. После дополнительных исследований обновления Windows и библиотека DLL OpenGL оказались отвлекающим маневром. Причиной этих симптомов был сбой вызова LoadLibrary() с GetLastError() == ERROR_NOT_ENOUGH_MEMORY. Смотрите мой ответ о том, как решить такие проблемы. Ниже оригинальный вопрос для исторического интереса. /изменить

Вьюер карт, который я написал на Python/wxPython для Windows с бэкендом C++, внезапно перестал работать без каких-либо изменений кода или даже перекомпиляции. Одни и те же исполняемые файлы работали неделями ранее (тот же Python, те же DLL, ...).

Теперь, когда я запрашиваю у Windows формат пикселей для использования с OpenGL (с ChoosePixelFormat()), я получаю сообщение MessageBox:

LoadLibrary failed with error 8:
Not enough storage is available to process this command

Сообщение об ошибке отображается при выполнении следующего фрагмента кода:

void DevContext::SetPixelFormat() {
    PIXELFORMATDESCRIPTOR pfd;
    memset(&pfd, 0, sizeof(pfd));
    pfd.nSize        = sizeof(pfd);
    pfd.nVersion     = 1;
    pfd.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
    pfd.iPixelType   = PFD_TYPE_RGBA;
    pfd.cColorBits   = 32;

    int pf = ChoosePixelFormat(m_hdc, &pfd);    // <-- ERROR OCCURS IN HERE
    if (pf == 0) {
        throw std::runtime_error("No suitable pixel format.");
    }

    if (::SetPixelFormat(m_hdc, pf, &pfd) == FALSE) {
        throw std::runtime_error("Cannot set pixel format.");
    }
}

На самом деле это DLL драйвера ATI GL, показывающая окно сообщения. Соответствующая часть стека вызовов такова:

                  ... More MessageBox stuff
0027e860 770cfcf1 USER32!MessageBoxTimeoutA+0x76
0027e880 770cfd36 USER32!MessageBoxExA+0x1b
*** ERROR: Symbol file not found. Defaulted to export symbols for C:\Windows\SysWOW64\atiglpxx.dll -
0027e89c 58471df1 USER32!MessageBoxA+0x18
0027e9d4 58472065 atiglpxx+0x1df1
0027e9dc 57acaf0b atiglpxx!DrvValidateVersion+0x13
0027ea00 57acb0f3 OPENGL32!wglSwapMultipleBuffers+0xc5e
0027edf0 57acb1a9 OPENGL32!wglSwapMultipleBuffers+0xe46
0027edf8 57acc6a4 OPENGL32!wglSwapMultipleBuffers+0xefc
0027ee0c 57ad5658 OPENGL32!wglGetProcAddress+0x45f
0027ee28 57ad5dd4 OPENGL32!wglGetPixelFormat+0x70
0027eec8 57ad6559 OPENGL32!wglDescribePixelFormat+0xa2
0027ef48 751c5ac7 OPENGL32!wglChoosePixelFormat+0x3e
0027ef60 57c78491 GDI32!ChoosePixelFormat+0x28
0027f0b0 57c7867a OutdoorMapper!DevContext::SetPixelFormat+0x71 [winwrap.cpp @ 42]
0027f1a0 57ce3120 OutdoorMapper!OGLContext::OGLContext+0x6a [winwrap.cpp @ 61]
0027f224 1e0acdf2 maplib_sip!func_CreateOGLDisplay+0xc0 [maps.sip @ 96]
0027f240 1e0fac79 python33!PyCFunction_Call+0x52
                  ... More Python stuff

Я выполнил Центр обновления Windows две недели назад и заметил некоторые сбои (например, при изменении размера окна), но моя программа по-прежнему работала в основном нормально. Только сейчас перезагрузился, винда установила еще 1 обновление, и дальше ChoosePixelFormat() не прохожу. Однако последним установленным обновлением было KB2998527, обновление часового пояса России?!

Вещи, которые я уже проверил:

  • Перекомпиляция не помогает.
  • Перезагрузка и запуск без запуска других программ не работает.
  • Потребление памяти моей программой всего 67 Мб, памяти не хватает.
  • Много свободного места на диске (~50 ГБ).
  • HDC m_hdc получается из HWND панели дисплея и кажется действительным.
  • Изменение командной строки компоновщика не работает.

Должен ли я обновить свои графические драйверы или откатить обновления? Любые другие идеи?

Дамп системных данных: Windows 7 Ultimate SP1 x64, 4 ГБ ОЗУ; HP EliteBook 8470p; Python 3.3, wxPython 3.0.1.dev76673 msw (феникс); доступ к структурам данных C++ через SIP 4.15.4; Код C++, скомпилированный с помощью Visual Studio 2010 Express, отладочная сборка с /MDd.


person Christian Aichinger    schedule 25.09.2014    source источник


Ответы (1)


У меня заканчивалось виртуальное адресное пространство.

По умолчанию LibTIFF считывает изображения TIF, сопоставляя их с памятью (mmap() или CreateFileMapping()). Это нормально для фотографий вашей жены, но оказывается плохой идеей для гигабайтных топографических растровых карт Альп.

Это было трудно диагностировать, потому что LibTIFF молча возвращался к read(), если отображение памяти не удавалось, поэтому раньше никогда не было явной ошибки. Кроме того, отображаемая память не считается рабочей памятью Windows, поэтому диспетчер задач показывал 67 МБ, хотя на самом деле почти все виртуальное адресное пространство было израсходовано.

Это взорвало сейчас, потому что я недавно добавил больше изображений TIF в свою базу данных. LoadLibrary() начал давать сбой, потому что не смог найти адресного пространства для размещения новой библиотеки. GetLastError() вернул 8, то есть ERROR_NOT_ENOUGH_MEMORY. То, что это произошло в библиотеке ATI OpenGL, было просто совпадением.

Решение состояло в том, чтобы передать "m" в качестве флага TiffOpen(), чтобы отключить ввод-вывод с отображением памяти.

Диагностировать это легко с помощью инструмента Windows SysInternals VMMap (ссылка на документацию), которая показывает, какая часть виртуального адресного пространства процесса занята кодом/кучей/стеком/сопоставленными файлами/общими данными/и т. д.

Это должно быть первым, что нужно проверить, если LoadLibrary() или CreateFileMapping() не работает с ERROR_NOT_ENOUGH_MEMORY.

person Christian Aichinger    schedule 25.09.2014
comment
При работе с очень большими наборами изображений я рекомендую использовать Vips: vips. ecs.soton.ac.uk/index.php?title=VIPS - person datenwolf; 26.09.2014