我一直在 MS Windows 下使用 OpenGL 编写服务器端离屏渲染。工作流程包括以下步骤:
客户端发送体绘制请求。
服务器接收到请求,派生一个工作线程以使用请求中包含的参数进行一些光线投射。
服务器检索渲染图像,将其发送到客户端并终止工作线程。
一开始它工作得很好。但是,在 10,000 个请求之后,wglMakeCurrent() 将失败并且可以检测到显着的内存泄漏。所以我做了一个简化的测试程序,它只包含 OpenGL 上下文的创建和删除。如下图所示。wglMakeCurrent() 在大约 10,000 次循环后总是失败。有人可以告诉我代码是否有问题吗?我使用的是 Nvidia Quadro GPU,驱动版本是 307.45,操作系统是 Windows 7 64 位。
#include <cstdio>
#include <windows.h>
#include <tchar.h>
#include <process.h>
LRESULT CALLBACK WndProc_GL(HWND handle, UINT message, WPARAM w_param, LPARAM l_param)
{
return DefWindowProc(handle, message, w_param, l_param);
}//-------------------------------------------------------
unsigned int __stdcall OpenglThreadProc(void *ptr_input)
{
HINSTANCE inst_handle = GetModuleHandle(NULL);
WNDCLASS wnd_class = {CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
(WNDPROC)WndProc_GL,
0, 0, inst_handle, NULL, NULL, NULL, NULL,
_T("OpenGL Hidden Window Class")
};
if (!RegisterClass(&wnd_class)) return 0;
HWND window_handle = CreateWindow(_T("OpenGL Hidden Window Class"),
_T("Window For OpenGL"),
WS_OVERLAPPEDWINDOW|WS_CLIPSIBLINGS|WS_CLIPCHILDRE N, 0, 0, 256, 256,
NULL, NULL, inst_handle, NULL);
if (!window_handle) return 0;
HDC dc_handle = GetDC(window_handle);
PIXELFORMATDESCRIPTOR ogl_pfd = {sizeof(PIXELFORMATDESCRIPTOR), 1,
PFD_SUPPORT_OPENGL,
PFD_TYPE_RGBA, 32,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
24, 8, 0,
PFD_MAIN_PLANE,
0, 0, 0, 0
};
int pixel_format = ChoosePixelFormat(dc_handle, &ogl_pfd);
if (!SetPixelFormat(dc_handle, pixel_format, &ogl_pfd)) return 0;
HGLRC rc_handle = wglCreateContext(dc_handle);
if (!rc_handle || !wglMakeCurrent(dc_handle, rc_handle)) return 0;
_tprintf_s(_T("Executing Thread %d.\n"), *(reinterpret_cast<int*>(ptr_input)) + 1);
// Deletes OpenGL context and destroys window.
wglMakeCurrent(NULL, NULL);
wglDeleteContext(rc_handle);
ReleaseDC(window_handle, dc_handle);
DestroyWindow(window_handle);
UnregisterClass(_T("OpenGL Hidden Window Class"), GetModuleHandle(NULL));
return 1;
}//--------
int main (const int argc, TCHAR *argv[])
{
int i = 0;
for (; i < 20000; i++) {
HANDLE running_thread = reinterpret_cast<HANDLE>(_beginthreadex(NULL, 0,
OpenglThreadProc, &i, 0, NULL));
WaitForSingleObject(running_thread, INFINITE);
CloseHandle(running_thread);
}
return 1;
}//---------
我发现这个测试程序有些令人困惑。wglMakeCurrent() 每次被调用时都会创建一个 Windows 用户对象,但是这个对象并没有在 wglDeleteContext() 中释放。即使在worker终止后它仍然存在,导致内存泄漏。在 Windows 下存在每个进程的用户对象限制,因此程序最终会失败。
当上下文创建/删除的代码移动到主线程时,wglMakeCurrent() 在第一次调用后不会创建新的用户对象。所以看起来 wglMakeCurrent() 只在新线程中创建新的用户对象。但是由于 OpenGL 上下文被显式删除并且线程被终止,与该上下文相关的资源也应该被释放。我不确定这是我的代码或驱动程序的问题。有人可以帮我吗?