我一直在MS Windows下用OpenGL编写服务器端的屏幕外渲染。工作流程包括以下步骤:
客户端发送卷渲染请求。
服务器收到请求,请求工作线程使用请求中包含的参数进行一些光线投射。
服务器检索渲染的图像,将其发送到客户端并终止工作线程。
一开始工作正常。但是,在10,000个请求之后,wglMakeCurrent()将失败并且可以检测到显着的内存泄漏。所以我制作了一个简化的测试程序,它只包含OpenGL上下文创建和删除。它如下所示。大约10,000次循环后,wglMakeCurrent()总是失败。有人可以告诉我代码是否有问题?我使用的是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()中发布。即使在工作程序终止后它仍然存在,导致内存泄漏。 Windows下的用户对象存在每进程限制,因此程序最终会失败。
当上下文创建/删除代码移动到主线程时,wglMakeCurrent()在第一次调用后不会创建新的用户对象。所以似乎wglMakeCurrent()只在新线程中创建新的用户对象。但是,由于OpenGL上下文被显式删除并且线程终止,因此也应该释放与该上下文相关联的资源。我不确定这是我的代码或驱动程序的错误。有人可以帮我吗?