본문 바로가기
컴퓨터/디버깅

a required resource was unavailable

by adnoctum 2011. 8. 7.


   DC를 제대로 해제하지 않을 경우, 프로그램이 지속적으로 느려지다가 결국은 멈추거나 a required resource was unavailable 이라는 오류 메세지가 나타난다. 그리고 이 경우 GDI object 가 사용된 것이기 때문에 다음과 같이 화면의 갱신이 제대로 일어나지 않게 된다.

환경 : Visual C++ 10.0 (VS2010) on Windows 7 Professional SP1, 64 bit



위 그림에서 검게 표시된 부분이 WM_PAINT message 를 받아서 다시 그려져야 하지만 아직 그려지지 못한 부분들이다. 심지어 capture program으로 capture조차 제대로 되지 않는다. 오류 메세지 또한 정확히 나타나지 않고, 다음과 같이 나타난다.   

  



우선, 이러한 경우는 일반적으로 GDI에 관련된 오류임을 경험적으로 알 수 있고, 또한 화면 갱신이 제대로 되지 않는 것에서 더욱 GDI 문제임을 추측해 볼 수 있었다. 그래서 작업 관리자를 실행시켜서 확인을 해 보았다.




지금 작성하고 있는 프로그램이 MetaGenePlot.exe 라는 프로그램인데, 메모리는 별로 많이 차지하지 않는 것을 알 수 있다. 그래서 작업관리자에서 GDI object 를 얼마나 갖고 있는지를 보기 위해 위처럼 이 값이 나오도록 설정하고 값의 변화 여부를 살펴 보았다. 그 결과 계속 그 값이 증가하였고, 위처럼 결국 9,999 개가 되었을 때 오류가 나면서 멈추었다.


   이런 경우 문제의 원인은 거의 일정한데, GetDC 로 얻은 자원을 제대로 Release 해주지 않은 것이다. 즉,

Get 으로 얻은 것은 Release 로 놓아 준다.
Create로 만든 것은 DeleteDC 류로 삭제해 준다.

는 원리를 지키지 않은 것이다. 이런 경우, 보통 한두개를 처리할 때는 문제가 생기지 않지만 지금처럼 100개가 넘어가게 되면 결국 멈추거나, 하여튼 문제가 생긴다. 그래서 GetDC 를 하는 부분을 살펴 보았다. 나는 GetDC 를 하면 곧바로 ReleaseDC 를 하면서 코딩을 하기 때문에 이런 경우가 과연 있나 의심스러웠지만 역시나 있었다. 바로 다음과 같은 부분.

  473     CDC *pDCC = CDC::FromHandle(AfxGetMainWnd()->GetDC()->GetSafeHdc()); 


지금은 문제를 해결한 상태[각주:1]에서 다시 되짚어 보느라 pDCC 처럼 이상한 이름을 사용했는데, 여하튼 위처럼 main window의 DC를 얻어서 이로부터 CDC 임시 객체를 만드는 과정이 있었다. 이 함수를 사용하는 class가 CWnd 를 상속받은 것이 아니기 때문에[각주:2] DC를 갖지 않고 있기 때문에 위처럼 했었는데, 나는 FromHandle 이 임시로 CDC 를 만든다는 사실 때문에 Release를 해줄 생각을 못 했었는데, 코드에서 보면 알 수 있듯이 main window가 GetDC로 DC를 얻고 있다. 따라서 이 상태에서 Release를 하지 않고 이 부분을 계속 호출하면 결국 GDI object 를 너무 많이 얻어 놓기만 해서 에러가 난다. 따라서 다음과 같이 Release를 해주어야 한다.

  

474     AfxGetMainWnd()->ReleaseDC(pDCC);

 

좌우지간 Get/Release, Create/Delete 의 원리를 잊지 않도록 해야 한다.
  1. 아예 설계 자체가 약간 바뀌었다. [본문으로]
  2. 약간이 고민 끝에 상속받지 않기로 결정했었다. [본문으로]