핸들 누수 파악하자
작업 관리자나 Process Explorer에는 열(Column)을 확장하는 옵션이 있다. 보통 메모리, 가상 메모리, 핸들, 스레드 정도를 추가하고, 경우에 따라 GDI 개체 수 같은 항목도 선택한다. 프로그램 시작할 때의 핸들 수와 나중의 핸들 수가 상당히 차이 난다면 핸들 누수가 있다고 보면 된다.
어느 핸들이 문제인가?
Process Explorer를 연다. [View/Show Lower Pane] 옵션을 선택한다. 이제 [View/Lower Pane View/Handles]를 선택하면 프로세스가 열어놓은 핸들 목록이 아래 쪽 화면에 표시된다. 기본적으로 핸들의 타입과 이름, 그리고 값 정도를 보여주는데, [View/Select Columns/Handle]에 들어가면 Access Mask나 Object Address 옵션이 있다. 이 두 옵션은 선택해두자. 마지막으로 [View/Show Unnamed Handles and Mappings]를 고르면 이름 없는 핸들까지 모두 보인다. 프로그래밍하다 보면 핸들 이름을 정해주지 않는 일이 잦기 때문에 반드시 이 옵션을 선택하자.
정확한 문제 지점을 찾아내자
문제 지점을 알아내는 방법은 많지만, 여기선 Application Verifier를 쓰겠다. Application Verifier를 실행시키고, [File/Add Application]에서 디버깅하고자 하는 대상 애플리케이션을 선택한다. 오른쪽 화면에서 [Basics/Handles]만 선택한 후, Save 버튼을 누른다.
WinDbg를 실행시키고 대상 애플리케이션을 열거나(File/Open Executable)나 대상 애플리케이션에 연결한다(File/Attatch a Process). Application Verifier에 대상 애플리케이션을 등록해놓았기 때문에, 실행시키자마자 애플리케이션은 중지(Break)된다. 이제 [Debug/Go] 또는 F5를 눌러서 원하는만큼 애플리케이션을 실행시킨다. 충분하다고 생각될 때 다시 [Debug/Break]를 누른다. 이제 트레이스할 일만 남았다.
0:013>.sympath
Symbol search path is: SRV*http://msdl.microsoft.com/download/symbols
0:014> !htrace
--------------------------------------
Handle = 0x00000048 - CLOSE
Thread ID = 0x00000a40, Process ID = 0x00000aa4
0x7c809b8b: kernel32!CloseHandle+0x00000051
0x003a4df9: vfbasics!AVrfpCloseHandle+0x00000089
0x00584fe2: DEBUG_TestClient!FClientxxxx::~FClientxxxx::~+0x00000092
0x00562b00: DEBUG_TestClient!FClient----::~FClient+0x00000100
0x0056295b: DEBUG_TestClient!FClient****::`scalar deleting destructor'+0x0000002b
0x00562728: DEBUG_TestClient!FClient####::Delete+0x00000138
--------------------------------------
이제 트레이스 결과를 보고 디버깅하면 된다.
주의
-
실제로 트레이스를 해보면 로그가 엄청나게 길어서 WinDbg 화면에 다 표시되지 않는다. 이런 경우엔 !htrace를 하기 전에 [Edit – Open/Close Log File]에서 로그 파일을 지정해주면 된다.
-
트레이스가 끝났으면 Application Verifier에 등록해 대상 애플리케이션을 삭제해야 한다. 그렇지 않으면 매번 실행시킬 때마다 중지(Break)된다. 디버거에 연결해주기 전까지 그 상태로 있으니 곤란하다.
혹시나 그래도 문제가 해결되지 않으면 레지스트리 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\Current Version\Image File Execution Options\대상 애플리케이션]을 지우면 된다.