0

稍后编辑:经过更多调查,Windows 更新和 OpenGL DLL 是红鲱鱼。这些症状的原因是LoadLibrary()呼叫失败GetLastError() == ERROR_NOT_ENOUGH_MEMORY。请参阅我的答案以了解如何解决此类问题。以下是历史兴趣的原始问题。/编辑

我用 Python/wxPython for 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.");
    }
}

它实际上是一个显示消息框的 ATI GL 驱动程序 DLL。调用堆栈的相关部分是这样的:

                  ... 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 更新,并注意到一些小故障(例如,在调整窗口大小时),但我的程序仍然可以正常工作。刚才我重新启动了,Windows 又安装了 1 个更新,我再也无法通过 ChoosePixelFormat()了。但是,最后安装的更新是 KB2998527,俄罗斯时区更新?!

我已经检查过的事情:

  • 重新编译不会使它工作。
  • 在没有其他程序运行的情况下重新启动和运行不起作用。
  • 我的程序的内存消耗只有 67 MB,我没有内存不足。
  • 大量可用磁盘空间(~50 GB)。
  • HDC m_hdc是从显示面板获得的,HWND似乎是有效的。
  • Changing my linker commandline doesn't work.

Should I update my graphics drivers or roll back the updates? Any other ideas?

System data dump: Windows 7 Ultimate SP1 x64, 4GB RAM; HP EliteBook 8470p; Python 3.3, wxPython 3.0.1.dev76673 msw (phoenix); access to C++ data structures via SIP 4.15.4; C++ code compiled with Visual Studio 2010 Express, Debug build with /MDd.

4

1 回答 1

4

I was running out of virtual address space.

By default, LibTIFF reads TIF images by memory-mapping them (mmap() or CreateFileMapping()). This is fine for pictures of your wife, but it turns out it's a bad idea for gigabytes worth of topographic raster-maps of the Alps.

This was difficult to diagnose, because LibTIFF silently fell back to read() if the memory mapping failed, so there never was an explicit error before. Further, mapped memory is not accounted as working memory by Windows, so the Task-Manager was showing 67MB, when in fact nearly all virtual address space used up.

This blew up now because I added more TIF images to my database recently. LoadLibrary() started failing because it couldn't find any address space to put the new library. GetLastError() returned 8, which is ERROR_NOT_ENOUGH_MEMORY. That this happened within ATI's OpenGL library was just coincidence.

The solution was to pass "m" as flag to TiffOpen() to disable memory mapped IO.

Diagnosing this is easy with the Windows SysInternals tool VMMap (documentation link), which shows you how much of the virtual address space of a process is taken up by code/heap/stack/mapped files/shareable data/etc.

This should be the first thing to check if LoadLibrary() or CreateFileMapping() fails with ERROR_NOT_ENOUGH_MEMORY.

于 2014-09-25T23:37:11.090 回答