반응형

원래 평소에는 Debug 모드에서 위와 같이 깔끔하게 종료되는데

실수로 ID3D11Buffer 객체 하나를 Release 를 빼먹어서 

Reference Count 가 하나 남게 되었고

아래처럼 회수 하지 않은 COM 객체가 남았다고 알려주는데 문제는

아래 내용을 보고서는 도저히 어떤 객체가 남았는지 알 수 없었다

 

그래서 열심히 구글링 하면서 찾아본 끝에

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

 

 

그나마 쉽게 추적할 수 있는 방법을 알아냈다

 

//WinMain

#ifdef _DEBUG
void D3D메모리누수체크()
{
	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"▽▽▽▽▽▽▽▽▽▽ Direct3D Object ref count 메모리 누수 체크 ▽▽▽▽▽▽▽▽▽▽▽\r\n");
	debug->ReportLiveObjects(DXGI_DEBUG_D3D11, DXGI_DEBUG_RLO_DETAIL);
	OutputDebugStringW(L"△△△△△△△△△△ 반환되지 않은 IUnknown 객체가 있을경우 위에 나타납니다. △△△△△△△△△△△△\r\n");

	debug->Release();
}
#endif


int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
	_In_opt_ HINSTANCE hPrevInstance,
	_In_ LPWSTR lpCmdLine,
	_In_ int nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);


	// System 객체 생성
	SystemClass_10* System = new SystemClass_10;
	if (!System)
	{
		return -1;
	}

	// System 객체 초기화 및 실행
	if (System->Initialize())
	{
		System->Run();
	}

	// System 객체 종료 및 메모리 반환
	System->Shutdown();
	SAFE_DELETE(System);


#ifdef _DEBUG
	D3D메모리누수체크();
#endif
	return 0;
}

win 메인 함수가 있는 cpp 파일에 D3D메모리누수체크() 함수를 위와 같이 정의하고 return 0; 바로 위에서 호출한다

물론 위의 "D3D메모리누수체크" 같은 한글이름은 안써도 된다, 알아보기 쉽게 한글로 써놓은 것이다, 위의 참고자료 글에서는 list_remaining_d3d_objects() 라고 함수이름을 지었다

 

그 다음  Debug 모드로 실행뒤 종료하고 Output 창을 좀 올려다 보면

 

위와 같이 나타난다, 

위 내용은 사실 위 코드의 D3D메모리누수체크() 함수안에 아래와 같은 부분이 실행된것이다

OutputDebugStringW(L"▽▽▽▽▽▽▽▽▽▽ Direct3D Object ref count 메모리 누수 체크 ▽▽▽▽▽▽▽▽▽▽▽\r\n");
debug->ReportLiveObjects(DXGI_DEBUG_D3D11, DXGI_DEBUG_RLO_DETAIL);
OutputDebugStringW(L"△△△△△△△△△△ 반환되지 않은 IUnknown 객체가 있을경우 위에 나타납니다. △△△△△△△△△△△△\r\n");

OutputDebugStringW 의 내용은 사실 중요하지 않다, 필자는 일부러 알아보기 쉽게 한글과 특수문자로

"▽▽▽▽▽▽▽▽▽▽ Direct3D Object ref count 메모리 누수 체크 ▽▽▽▽▽▽▽▽▽▽▽\r\n"

위와 같이 써놨는데, 구지 이렇게 해놓지 않아도 된다

어쨋든 위 Output 내용을 다시 보면 ID3D11Buffer 객체가 반환되지 않은 것을 알 수 있다

그러나 여전히 어떤 ID3D11Buffer 객체인지는 알아보기 힘들다

 

 

그렇기 때문에 

위와 같이 모든 D3D COM 객체를 초기화 할때 SetPrivateData 함수를 실행해서

각각의 D3DDebugObjectName 을 따로 지정해준다

필자는 D3D COM 객체가 어떤 클래스에 멤버 변수 일때는

"LightShaderClass::m_cameraBuffer"    

와 같이 D3DDebugObjectName지정해줬다

 

SetPrivateData(

 WKPDID_D3DDebugObjectName,

 sizeof("LightShaderClass::m_cameraBuffer") - 1, //끝자리 0을 제외한 문자열길이

  "LightShaderClass::m_cameraBuffer"); // D3DDebugObjectName

 

 

위와 같이 지정해준뒤 다시 디버그 모드로 실행뒤 종료하고 Output 창을 살펴보면

위에 지정한 그대로 나오는 것을 알 수 있다

이제 어느 클래스의 어떤 COM 객체가 회수를 못했는지 알았으니, 코드를 다시 올바르게 수정하여

COM객체를 회수하도록 하고 

다시 디버그 모드로 실행뒤 종료하고 Output 창을 살펴보면

 

 

위의 빨간색 사각형으로 표시된 부분에 이전과는 다르게 아무런 내용도 나타나지 않은걸 알 수 있다

즉 모든 COM 객체가 깔끔하게 회수 된것이다.

 

 

 

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

 

 

반응형

+ Recent posts