본문 바로가기

일하면서 사용한 짧은 지식/C++, DirectX11

DirectX11 COM 객체 메모리 누수 원인 추적하기

https://social.msdn.microsoft.com/Forums/SECURITY/en-US/2b043a3a-2320-4cf5-8b9b-4fe5c2a7f119/what-does-setprivatedata-mean-in-directx-11?forum=vcgeneral

 

What does SetPrivateData(...) mean in DirectX 11?

I've read the documentation about SetPrivateData but I don't know how to use it, I know that it's a memory leak detection according to the documentation but I don't know how to use it. There are many Microsoft examples of how to use it, but they don't show

social.msdn.microsoft.com

 

 

상황

DirectX11로 구현한 렌더러를 사용하는 플레이어가 그래픽카드 영역을 넘나들 때,

리소스가 제대로 해제가 안되는지 메모리, 쓰레드, 핸들이 증가하는 현상이 발생하였다.

위 현상을 해결하기 위해 위 사이트의 내용대로 아래와 같은 방법이 사용되었다.

 

 

 

해제안된 DirectX11 COM 객체를 추적하는 함수 정의

 

#ifdef _DEBUG
#include <dxgidebug.h>
#endif

#pragma comment(lib, "dxguid.lib")

#ifdef _DEBUG
void list_remaining_d3d_objects()
{
	HMODULE dxgidebugdll = GetModuleHandleW(L"dxgidebug.dll");
	decltype(&DXGIGetDebugInterface) GetDebugInterface = reinterpret_cast<decltype(&DXGIGetDebugInterface)>(GetProcAddress(dxgidebugdll, "DXGIGetDebugInterface"));

	IDXGIDebug *debug;

	GetDebugInterface(IID_PPV_ARGS(&debug));

	OutputDebugStringW(L"Starting Live Direct3D Object Dump:\r\n");
	debug->ReportLiveObjects(DXGI_DEBUG_D3D11, DXGI_DEBUG_RLO_DETAIL);
	OutputDebugStringW(L"Completed Live Direct3D Object Dump.\r\n");

	debug->Release();
}
#endif

 

Device 생성할 때 D3D11_CREATE_DEVICE_DEBUG 플래그 설정.

생성 함수에 flag를 파라미터로 넘겨 DEBUG 옵션을 설정하고,

객체 사용이 끝난 뒤 해제 로직을 실행하는 부분 다음에,

위에서 정의한 함수를 실행하여 해제 안된 COM 객체 추적

 

UINT flags = 0;

//DEBUG flag 설정
#ifdef _DEBUG
flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

//flag 설정한대로 Device 생성
HRESULT ret = D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, flags, fls, 2, D3D11_SDK_VERSION, &d3d11dev, &fl, &d3d11devctx);

//... Release() 호출하여 Device 해제 후

//해제안된 COM객체 추적
#ifdef _DEBUG
list_remaining_d3d_objects();
#endif

 

 

Refcount가 0이 아닌 것을 찾으면 해제 안된 것을 추적할 수 있다.

 

 

 

우리 회사 코드는 COM 객체가 많지 않아 위 방법으로도 충분했지만,

COM 객체가 같은 종류가 많아서 그 사이에 구분이 필요하다면,

링크를 걸어둔 사이트의 답변처럼 SetPrivateData를 사용자가 설정하면,

아래와 같이 지정한 이름으로 추적 가능하다.

 

 

d3d11dev->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof("Device") - 1, "Device");
d3d11devctx->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof("DeviceCtx") - 1, "DeviceCtx");