'Visual Studio'에 해당되는 글 3건

  1. 2012.06.21 Visual Studio 2010에서 std::vector<std::string>::insert 메모리 릭
  2. 2008.10.02 Handle leak 찾기 (3)
  3. 2008.08.18 Break point

inserting in a std::vector of std::string causes memory leak

 

위와 같은 보고가 있었군요. 요약을 하자면 아래 코드를 실행 하면 메모리 릭이 발생한다는 것.

#include "stdafx.h"

#include <string>
#include <vector>

int _tmain(int argc, _TCHAR* argv[])
{
    // debug memory leaks
    _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

    {
         std::vector<std::string> vec;
         vec.reserve(3);
         vec.push_back("1");
         vec.insert(vec.begin(), 2, "2");
     }
 
     return 0;
}

 

VS 2010 SP1에서 패치 되었다고 하니 어서 어서 패치해야 할 듯..

Posted by kukuta

댓글을 달아 주세요

이 글의 대상은 윈도우 프로그래밍에 대해서 어느 정도 이해를 하고 있는 사람들을 대상으로 합니다. 기본적으로 핸들과 커널 오브젝트에 대한 개념에 대해 알고 있어야 하며(모른다면 여기로), 디버깅에 대해서 약간의 기본적 지식을 가지고 계시는 것이 좋습니다.

본 포스트는 디버깅에 관련된 툴들의 사용법에 대해서 다루고 있으며, 자세한 사용법 보다는 기본적인 사용법위주로 문제 해결에 관련된 부분만 다루고 있습니다. 보다 자세한 정보를 원하시면 해당 툴에 관련된 링크를 따라 가시면 많은 도움이 될 것입니다.


프로그래밍을 하다 보면 원하든 원하지 않든(거의 이 경우가 대부분이만) 종종 자원을 흘리고 다니는 경우가 있다. 여기서 말하는 자원이란 것은 파일이든, 메모리든 핸들이든 여러가지가 될 수 있지만 오늘은 특히 '핸들(handle)'의 누수를 어떻게 찾아 낼 수 있는가에 대해서 알아 보도록 하겠다.

핸들의 누수를 찾기 위해서는 아래와 같은 준비물이 필요하다 :
 - 핸들을 흘리고 있을 것이라 짐작되는 실행 프로그램

 - 윈도우를 깔면 기본적으로 제공되는 작업관리자(Task mananger)
 - Process Explorer(http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx)
 - Debugging Tools for Windows 패키지에 포함 되어 있는 Windbg
   (http://www.microsoft.com/whdc/DevTools/Debugging/default.mspx)
 ※ 링크가 깨어져 있을 경우는 구글에서 검색하시면 금방 찾을 수 있을 겁니다.
 ※
위의 준비물이 다 준비 되었다면 핸들 누수를 찾아 보도록 하자.

1. 이 어플리케이션에서 핸들이 새고 있을까요?
가장 먼저 해야 할 일은 어플리케이션이 핸들을 질질 흘리고 다니는지 아닌지 판단 해야한다. 판단하는 방법으로는 작업관리자를 이용하면 된다. 여기서 잠깐 작업관리자에 대한 사족을 달자면, 이 녀석은 프로세스에 대한 각종 유용한 정보를 알려 주는 녀석으로써, 앞으로도 디버깅 관련 포스팅에 약방에 감초 처럼 등장 할 녀석이다.

맨위의 매뉴에서 '보기>열선택'(영어로는 어떻게 쓰여져 있는지 모르겠다) 순서로 클릭해 들어가면 수많은 체크박스들이 보일 것이다. 그것들 중에 관심있는 박스에 체크를 하고 확인을 누르면 되겠다. 여기서는 핸들이 누수 되고 있는지 아닌지를 찾을 것이기에 '핸들 수'에 체크를 하자. 그럼 이제 부터 작업관리자의 프로세스 탭에서 '핸들'에 관련된 정보를 볼 수 있을 것이다.

핸들이 누수 되고 있을 거라고 생각 되는 프로세스의 핸들 숫자를 살펴 보자. 핸들 카운트가 늘어나고 있는가? 여기서 한가지 유의 할 점은 핸들 카운트가 늘어난다고 해서 무조건 누수라고 봐서는 안된다는 것이다. 단순히 사용하는 핸들이 많아서 핸들 카운트가 늘어 나는 것일 수도 있고, 캐싱이나 등을 위해서 일부러 핸들을 클로즈하지 않고 있는 것일 수 있다. 프로세스가 아무것도 하지 않고 아이들(idle) 상태에 있으면서도 핸들 카운트가 증가하고 있거나 감소하지 않는다면 의심해 볼만 하다.

2. 어떤 핸들이 새고 있을까요?
프로세스에서 핸들이 누수되고 있다고 확신을 가지고 있다면(위에서 어렵게 이야기 했지만, 핸들이 누수되고 있다는 사실을 판단하는 것은 직관적으로도 알 수 있는 쉬운 작업이다) 어떤 타입의 핸들이 누수되고 있는지 파악한다면 잘못을 바로 잡는데 상당히 시간을 절약 할 수 있을 것이다. 이럴 때 사용 할 수 있는 것이 바로 "Process Explorer"이라는 녀석이다.

이 녀석은 현재 선택된 프로세스에서 만들어 지고 있는 핸들의 타입에 대한 정보들을 일목요연하게 보여준다. 만일 이 녀석으로 프로세스를 감시 하고 있는데 줄어들지 않고 늘어 나기만 하는 핸들이 있다면 바로 그녀석이 누수의 원인. 어떤 타입의 핸들이 새고 있는지 알고, 핸들의 이름도 알 수 있으니 코드를 수정하는 것은 시간 문제다. 아래의 스크린샷은 파일 핸들을 지속적으로 만들어 내고 있는 프로세스를 모니터링 하고 있는 것이다 :

위에 보이는 HeapMemoryLeak라는 프로그램은 필자가 의도적으로 핸들 및 메모리등의 자원을 누수 하도록 만든 프로그램이다. 아래쪽 윈도우를 보면 똑같이 생긴 File 타입의 핸들들이 중복해서 만들어 지고 있는 것을 볼 수 있다.

"Process Explorer"를 사용하는 방법에 대해 좀 더 자세히 알고 싶다면, http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx 를 참고 하자.

3. Windbg 사용하기(Make use of Resource leak detection tools)
지금까지 1번과 2번의 과정에서 프로세스의 핸들 누수 여부를 결정하는 일, 어떤 타입의 핸들이 누수 되는지 구분하는 방법에 대해 알아 보았다. 하지만 핸들 누수라는 것이 언제나 정기적으로 발생하는 것도 아니고, 복잡한 환경에서 구동되는 프로그램이라면 동일한 파라메터에 동일한 시간이 지났음에도 불구하고 누수되는 양이나 누수되는 곳이 다를 수도 있다. 이럴 때 유용하게 사용 할 수 있는 것이 Windbg!htrace다.

htrace는 Windbg의 확장 기능으로 핸들의 OPEN과 CLOSE에 대해서 함수 호출 스택, 핸들을 열거나 닫은 프로세스 아이디, 쓰레드 아이디등을 추적 할 수 있으며, 결론적으로는 열리기는 했으되 닫히지 않은 모든 핸들들만을 선별하여 위에서 언급한 정보들을 제공 할 수 있다. 열리기만 하고 닫히지 않은 핸들은 누수되고 있을 확률이 높고, 어디서 만들었는지에 대한 정보도 제공해 주니 이 어찌 좋지 아니한가.

htrace에 대해서 시작하기 전에 windbg의 사용법에 대해서 기본적인 것을 알아 보자 :
1. Windbg.exe를 실행 한다. 
커맨드로 실행 해도 좋고, 시작 메뉴에서 부터 실행 해도 좋다. 일단 실행 하자.

2. 디버깅할 프로그램에 attach 하거나 Windbg에서 executable 파일을 로드한다.
디버깅하기 위해서는 이미지를 로드 해야 한다. Windbg가 로드하는 방법으로는 두 가지가 있는데 구동중인 프로세스에 Windbg를 붙이는 방법과 Windbg에서 디버깅할 프로세스를 로드 하는 방법이 있다.
 
구동 중인 프로세스에 붙이기(Attach to a running process)
 프로세스가 실행 중이어야 한다.
 프로세스 아이디를 이용하여 붙일 수 있다.
 windbg.exe -p PID
 혹은 프로세스 이름을 이용하여 붙일 수도 있다. 하지만 동일한 이름의 프로세스가 2개 이상이면 안 된다.
 windbg.exe -pn ProcessName
 혹은 GUI 모드에서 File>Attatch 를 하면 된다.

Windbg에서 executable파일 로드하기(Spawning new process)

 Windbg.exe [-o] ProgramName
 혹은 GUI 모드에서 File>Open Executable 을 하면 된다.

간단하게 나마 Windbg의 실행 방법에 대해서 알아 보았다. 이제 windbg에서 핸들이 누수되고 있을 것이라고 의심되는 프로세스를 로드하는 것은 끝났다. 이제 어떻게 htrace를 이용 할 것인가?

CommandLine: E:\Project\HeapMemoryLeak\Debug\HeapMemoryLeak.exe
Symbol search path is: *** Invalid ***
****************************************************************************
* Symbol loading may be unreliable without a symbol search path.           *
* Use .symfix to have the debugger choose a symbol path.                   *
* After setting your symbol path, use .reload to refresh symbol locations. *
****************************************************************************
Executable search path is:
ModLoad: 00400000 0041b000   HeapMemoryLeak.exe
...
(1774.368): Break instruction exception - code 80000003 (first chance)
eax=00251eb4 ebx=7ffd6000 ecx=00000003 edx=00000008 esi=00251f48 edi=00251eb4
eip=7c931230 esp=0012fb20 ebp=0012fc94 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
...
7c931230 cc              int     3

프로세스를 로드하면 제일 먼저 나오는 화면이다. 심볼 패스가 제대로 로드 안되었다는 에러메시지가 눈에 거슬리긴 하지만 무시하도록 하자. 가장 먼저 해야 할 일은 htrace를 활성화 시키는 것이다 :
0:001> !htrace -h
!htrace [handle [max_traces]]
!htrace -enable [max_traces]
!htrace -disable
!htrace -snapshot
!htrace -diff
0:001> !htrace -enable
Handle tracing enabled.
Handle tracing information snapshot successfully taken.

htrace가 활성화 되고나면 윈도우는 모든 핸들의 생성과 소멸에 관련된 호출에 대해서 기록하기 시작한다.
이제는 프로세스가 자원을 누수 할 수 있도록 프로세스를 구동 시키자(지금까지 프로세스는 블록킹 상태였다).

0:001> g

'g'를 누르게 되면 프로세스는 구동상태로 들어가게 되고, 자원을 누수하는데 필요한 자신의 일을 할 것이다. 자원 누수를 경험 할 수 있는 적정 시간이 경과 되고 난후 디버깅을 잠시 멈춰 주자. 맨위의 GUI 메뉴를 살펴 보면 '일시 정지' 버튼을 누르면 된다 :

(1774.254): Break instruction exception - code 80000003 (first chance)
eax=7ffd6000 ebx=00000001 ecx=00000002 edx=00000003 esi=00000004 edi=00000005
eip=7c931230 esp=003affcc ebp=003afff4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000246
ntdll!DbgBreakPoint:
7c931230 cc              int     3

프로세스가 정상적으로 블록킹 상태로 빠졌다면 이제 !htrace 명령으로 그동안 생성되고 소멸된 핸들을 찾아내면 된다 :

0:001> !htrace
--------------------------------------
Handle = 0x00000690 - OPEN
Thread ID = 0x00000368, Process ID = 0x00001774
0x7c801a4f: kernel32!CreateFileA+0x0000002b
0x102c43f5: MSVCR90D!open+0x000008a5
0x102c3e97: MSVCR90D!open+0x00000347
0x102c4fe0: MSVCR90D!sopen_s+0x00000020
0x102552bd: MSVCR90D!flsbuf+0x00000ddd
0x102565f5: MSVCR90D!fsopen+0x000001d5
0x10256644: MSVCR90D!fopen+0x00000014
0x0041147d: HeapMemoryLeak!main+0x0000003d
0x00411ad8: HeapMemoryLeak!__tmainCRTStartup+0x000001a8
--------------------------------------
...
Parsed 0x4 stack traces.
Dumped 0x4 stack traces.

간단하게 하기 위해 많은 부분을 생략 했다. 위의 로그에 나와 있는 부분들은 너무 직관적이라 따로 설명하지 않도록 하겠다. 다만 Handle = <value> - OPEN 의 경우 핸들 생성 콜을 나타내고 반대로 CLOSE라는 것이 있다는 것을 알아 두자. 동일한 핸들 값에 OPEN만 있고 CLOSE가 없는 녀석들이 바로 우리가 찾는 녀석들이다. 여기서 분명히 불평하시는 분 있을 것이다. 저 많은 로그들 사이에서 어떻게 특정녀석들을 찾냐고... 그래서 htrace는 획기적은 툴을 하나 더 제공한다. 바로 -diff 옵션이다.

바로 이 -diff를 사용하면 OPEN만 있고 CLOSE가 없는 모든 녀석들을 찾아 낼 수가 있다 :
0:001> !htrace -diff
Handle tracing information snapshot successfully taken.
0x32 new stack traces since the previous snapshot.
Ignoring handles that were already closed...
Outstanding handles opened since the previous snapshot:
--------------------------------------
0:001> !htrace -diff
Handle tracing information snapshot successfully taken.
0x32 new stack traces since the previous snapshot.
Ignoring handles that were already closed...
Outstanding handles opened since the previous snapshot:
--------------------------------------
Handle = 0x00000690 - OPEN
Thread ID = 0x00000368, Process ID = 0x00001774
0x7c801a4f: kernel32!CreateFileA+0x0000002b
0x102c43f5: MSVCR90D!open+0x000008a5
0x102c3e97: MSVCR90D!open+0x00000347
0x102c4fe0: MSVCR90D!sopen_s+0x00000020
0x102552bd: MSVCR90D!flsbuf+0x00000ddd
0x102565f5: MSVCR90D!fsopen+0x000001d5
0x10256644: MSVCR90D!fopen+0x00000014
0x0041147d: HeapMemoryLeak!main+0x0000003d
0x00411ad8: HeapMemoryLeak!__tmainCRTStartup+0x000001a8
--------------------------------------
... 

0x00000690의 값을 가진 핸들이 여전히 close 되지 않고 버티고 있는 것을 볼 수 있다. 이 프로그램은 파일을 열고 닫지를 않으니 모든 핸들이 줄줄줄 새는 것이 당연하다. 그리고 콜 스택을 살펴보면 tmain 함수에서 호출하는 fopen을 따라 핸들을 생성하는 것을 알 수 있다.

4. 관련 문서



이상 핸들 누수를 어떻게 감지하는지 알아 보았습니다. 글을 적고 있는 필자도 그렇게 위의 툴들에 해박한 지식을 가지고 있는 것이 아니라 공부하고 있는 처지이기에 많이 부족한 글이라 생각합니다만 이 정도 만으로도 충분히 어느정도의 핸들 누수는 잡아 내는데 도움을 줄 수 있을 것이라 생각하며 이만 포스트를 접도록 하겠습니다..

'도구의발견' 카테고리의 다른 글

cvs diff 출력 형식 보기  (0) 2008.12.11
키보드 리매핑하기(레지스트리 변경)  (7) 2008.12.05
Handle leak 찾기  (3) 2008.10.02
cvs 파일 상태 기호  (2) 2008.08.19
GDB Tutorial  (0) 2008.08.19
Break point  (0) 2008.08.18
Posted by kukuta

댓글을 달아 주세요

  1. Favicon of https://daewonyoon.tistory.com BlogIcon daewonyoon 2008.11.11 15:17 신고  댓글주소  수정/삭제  댓글쓰기

    유용한 글 잘 읽었습니다.

  2. ㅎㅎ 2011.06.22 00:44  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 감사합니다. 퍼갈게요 ^^

Break point

도구의발견 2008.08.18 21:50
버그 없는 프로그램을 만드는 것이 가장 좋은 방법이긴 하지만 현실적으로 처음 부터 그런 것을 만든다는 것은 디버거에 대한 모독이며 여지껏 나왔던 디버깅 관련 책들에 대한 도전이다. 말이 이상하긴 하지만 디버깅이 프로그래밍에서 빠져서는 안되는 중요한 요소라는 것을 강조하고 싶은 것이니 대충 '디버깅은 중요하다' 정도로 이해하고 넘어 가도록 하자.

이렇게 중요한 디버깅을 함에 있어서 Visual studio는 상당히 도움되는 툴들을 제공하고 있는데 그 중에 제일미로 꼽을 수 있는 것이 바로 '브레이크 포인트(Break point)'다. 여기 와서 브레이크 포인트가 뭐냐고 묻는다면...나도 할 말이 없다. 그냥 브레이크 포인트는 알고 있고 대충 visual studio에서 제공하는 기본적인 디버깅 관련 툴들은 사용 할 줄 안다는 가정하에 글을 진행 하도록 하겠다.

그럼 가장 먼저 알아야 할 것은 브레이크 포인트의 설정이다 :

1. 브레이크 포인트 설정

1.1 간단한 브레이크 포인트 설정

브레이크 포인트는 가장 간단하게는 소스 코드의 적절한 부분에 가서 <F9>를 누르는 방법과 소스 코드 에디터의 맨 왼쪽 빈 여백을 마우스로 클릭하는 방법이 있다. 너무 쉬운가? 그렇다면 좀 더 빨리 브레이크 포인트를 설정 하는 방법에 대해 알아 보자.

1.2 브레이크 포인트 정보 보기
'함수 혹은 클래스 이름을 이용하여 브레이크 포인트 설정'을 하기 전에 먼저 알아 두면 좋을 것이 있다. 바로 '브레이크 포인트 정보'다. 브레이크 포인트들에 관련된 세세한(?) 정보를 보여주는 아주 유용한 창이다. '브레이크 포인트 정보'창을 열기 위해서는 간단하게는 'Ctrl+Alt+B'를 누르는 방법이 있고, 조금 귀찮긴 하지만 메뉴를 이용하여 보기 위해서는 'Debug > Windows > Break Points'와 같이 찾아 갈 수 있다.

해당 윈도우에서 보여 주는 정보로는 브레이크 포인트의 이름(파일 이름과 라인으로 표시), 조건(Condition), 적중 횟수(Hit count) 등등이 있다. 자세한 설명은 다음 장에서 자세히 다루도록 하고 지금은 '브레이크 포인트들의 정보를 한번에 보여 주는 창이 있다' 정도를 알고 지나가도록 하자.

1.3 함수 혹은 클래스 이름을 이용하여 브레이크 포인트 설정
잠시 이야기가 다른 곳을 샜지만 다시 본론으로 돌아와서..브레이크 포인트를 걸어야 할 소스가 눈에 바로 보인다면 위의 방법 처럼 마우스나 <F9>를 이용하면 좋지만, 소스 코드 어디에 쳐박혀 있는 한참을 헤메야 하거나, 브레이크 포인트를 걸어야 할 곳이 한 두 곳이 아니라면 '함수 혹은 클래스 이름을 이용하여 브레이크 포인트 설정'하는 법을 알면 편하다.

위에서 설명한 '브레이크 포인트 정보'창을 띄워 보도록하자. Ctrl+Alt+B를 누르면 편하다. 키매핑을 변경했다면 직접 매뉴를 하나씩 클릭하면서 찾아 가도록 하자.

브레이크 포인트 정보 창을 띄웠다면 'New'를 클릭하자. 그냥 그 창에서 마우스 오른 클릭을 하여 '새 브레이크 포인트(New Break point)'를 선택해도 된다. 그럼 당장 눈에 보이는 것이 바로 함수(Function)탭이다.
사용자 삽입 이미지
현재 내가 사용하고 있는 Visual studio는 영문판이라 영어로 나오지만, 한글판을 사용하는 사람에게는 함수라고 한글로 나올것이다. 각설하고 위에 커서가 움직이는 곳에 브레이크 포인트를 걸 함수 이름을 적어 주면 만사 오케이다. 다만 C++같이 대소문자 구분을 하는 경우라면 여기에서도 대소문자를 구분해주어야 하고, 함수이름을 완벽하게 써줘야 한다는 것이다. 어줍잖게 쓰면 '정보가 부족한데도 계속 브레이크 포인트를 걸고 싶니?'라고 물어 온다. 괜시리 서로 피곤해지지 말고 한번에 잘 적어주자.

만일 함수가 중복(오버로드)된 것들이 많이 있다면 특정 클래스 내에서 한계를 긋고 싶기도 할 것이다. 그럴경우 C++이라면 네임스페이스를 찍어주는 것처럼 'ClassName::FunctionName'과 같은 형식으로 입력해주면 된다.  그림이 들어 가서 길어 보이기는 하지만 간단한 내용이다. 함수 이름 똑바로 써라. 그것이 핵심이다.

2. 특정 조건에서만 브레이크 포인트가 걸리도록 하기
디버깅을 하다 보면 매번 브레이크 포인트에 걸리는 것을 원하지 않을 경우가 있다. 예를 들어 for루프를 1000번 도는데 버그는 999번째에만 발생한다고 생각해 보자. 그럼 어떻게 할 것인가? Go next(F10)을 999번 눌러야 할까? 다행이 MS는 그렇게 멍청하지 않아 우리가 그토록 수고 할 필요가 없도록 했다. 간단하게 말하자면 특정 조건을 만족 할 경우에만 디버깅 중에 브레이크가 걸리 도록 할 수 있다는 말이다.

2.1 적중 횟수(Hit count)
위(1.2 브레이크 포인트 정보 보기)에서 한번 언급했고, 위의 'New Break point' 이미지에서도 확인했다. 바로 'Hit count'!! 한국말로 하자면 적중횟수가 되겠지만(혹자는 생략 횟수라고도 한다) 그냥 편하게 영어로 진행하도록 하겠다. 이 Hit point 라는 녀석의 용도가 무엇인고 하니, 바로 '지정된 코드가 특정 횟수 이상 반복 되기 전까지는 브레이크 포인트를 활성화 하지 않게 하는 것'이다. 이것을 이용하면 루프내에서 적절한 시기에 브레이크 포인트를 활성화 하는 것이 쉬워 진다.

Hit count를 설정하는 방법은 상당히 간단하다. 첫째로 소스 코드 에디터 왼쪽에 있는 브레이크 포인터(일명 빨간콩)을 오른쪽 클릭하여 'Breakpoint Porperties'를 클릭하는 것이다. 아니면 1.2장에서 설명한 '브레이크 포인트 정보'창에서 원하는 브레이크 포인트에 오른 클릭하여 Properties를 선택 해도 된다.
사용자 삽입 이미지
만일 기존의 브레이크 포인터에 속성을 조절하는게 아니라 새로운 브레이크 포인트를 만드는 것이라면 'New Break point'창에서도 Hit Count를 조절 할 수 있다.

Hit count는 기본값으로 항상 적용되도록 되어 있지만 총 네가지 방법으로 그 값을 조절 할 수 있다 :

적중 횟수 적용

설명

항상 중단(break always)

해당 위치에서는 항상 멈춘다.

적중 횟수가 같은 경우 중단

(break when the hit count is equal to)

해당 위치가 정해진 횟수만큼 실행 되었을 때 멈춘다. 횟수는 1부터 시작한다.

적중 횟수가 배수일 경우 중단

(break when the hit count is multiple of)

해당 위치의 실행 횟수가 x 배수인 경우 멈춘다.

적중 횟수가 크거나 같은 경우 중단

(break when the hit count is greater than or equal to)

적중 횟수가 정해진 횟수에 도달할 때까지 멈추지 않다가 그 후로는 계속 활성화.


간단하게 요약하자면 Hit count 기능을 잘 이용해 디버거에서 프로그램이 중단 되었을 때 프로그램이 얼마나 실행 되었는지 쉽게 유추 할 수 있다는 것이다. 그리고 힘들게 go next를 누를 필요가 없다는 소리이기도 하다.

2.2 조건 표현식(Condition)
위에서는 특정 횟수 이상 코드를 실행하게 되면 브레이크 포인트가 활성화 되는 방법에 대해 알아 보았다. 그렇다면 이제는 횟수가 아닌 특정 조건일 경우에만 브레이크 포인트가 활성화 되는 방법에 대해 알아 보도록 하자. 여기서는 Condition이라고 하겠다. 1.2 장에서 이미 언급한 바가 있고, 이제껏 나온 그림들을 봐도 Hit count가 나올 때 항상 빼 놓지 않고 나오는 'Condition' 이 있다. 한글로 번역을 하자면 '조건 표현식' 정도가 되겠지만 메뉴 그대로를 따라 가도록하자(한글 VS에는 뭐라고 나오는지 모르겠다).

이 'Condition'이라는 것의 용도가 무엇인고 하니 특정 조건을 만족하거나, 마지막으로 비교된 후로 값이 변경되었을 때만 브레이크 포인트를 활성화 시킬 수 있는, 우리들의 디버깅 시간을 눈물나게 고마울 정도로 줄여 주는 유용한 툴인 것이다.

일반적으로 'Condition'은 우리가 if 문안에서 생각할 수 있는 표현식을 지원한다. 그리고 지역 변수나 전역 변수들은 현재 실행 중인 컨텍스트에서 평가하기 때문에 이 표현식에서 사용이 가능하다. 기본적으로 조건식이 참인 경우 브레이크 포인트를 활성화 시키도록 되어 있으나 간단한 변경을 통해서 값이 변경되는 경우에 브레이크 포인트를 활성화 시킬 수 있다.
사용자 삽입 이미지
참고 할 사항은 조건이 처음으로 평가되는 순간이 조건을 입력 할 때가 아니라, 조건이 처음으로 실행 되는 순간이라는 것이다. 하지만 조건은 아직 한번도 평가된 적이 없기 때문에 디버거는 내부에 조건식에 필요한 정보를 저장하지 못하고 있다. 결국 브레이크 포인트가 활성화 되기 위해서는 해당 조건이 두번 실행 되는 경우다.

간단 예를 만들기 위해 특정 상황을 가정해 보자. 멀티 쓰레드를 이용하는 어플리케이션을 디버깅을 하다보면 여러 쓰레드에서 동일한 코드를 호출하여 쓰레드 하나 마다 디버깅이 멈춰져 매우 귀찮음을 느낀 사람들이 있을 것이다. 특정 쓰레드일 경우일 경우만 해당 브레이크 포인트를 활성화 시키는 조건식을 만들어 보도록 하자 :
  1. 먼저 쓰레드 아이디를 알아야 한다. 쓰레드 아이디는 디버깅 중에만 알 수 있다. 디버깅을 시작하고 'Ctrl+Alt+H' 나 'Debug > Windows > Threads' 를 선택하면 쓰레드 정보를 보여주는 창을 띄울 수 있다. 해당 정보 중에서 필요한 쓰레드(이름이라던지 location이라던지 활성화 화살표를 참고 하면 알 수 있다)를 찾아 아이디를 외운다(아니면 어디 적어 둬도 된다).
  2. 조건식을 입력 하는 창(Breakpoint Condition)에서 '*(long*)($TIB+0x24) == <thread id>' 조건식을 입력한다. $TIB는 쓰레드 관련 정보가 저장되어 있는 레지스터를 나타내고, 거기에 0x24를 더해주는 것은 나중에 쓰레드 정보 구조체를 살펴 보면 알 수 있을 것이다. 지금은 그냥 그러려니 하고 넘어가도록 하자.
  3. 마지막으로 디버깅을 계속 진행 하면 위에서 지정한 쓰레드 아이디를 가진 쓰레드에서만 함수가 호출 되는 것을 확인하자.
이 외에도 디버깅을 하는데 도움을 주는 도구들이 많이 있다. 예를 들자면 위에서 언급한 $TIB 같은 레지스터 같은 것들이다. 기회가 닿는다면(내가 게으름을 이긴다면...) 다음 번에는 레지스터를 이용한 디버깅에 대해서 다뤄보고 싶다.

참고 : Debugging Applications for Microsoft .Net and Microsoft Windows

'도구의발견' 카테고리의 다른 글

cvs 파일 상태 기호  (2) 2008.08.19
GDB Tutorial  (0) 2008.08.19
Break point  (0) 2008.08.18
vim Undo & Redo  (3) 2008.08.06
개발자를 위한 .vimrc 설정  (0) 2008.07.15
SVN 사용하기  (0) 2008.04.30
Posted by kukuta

댓글을 달아 주세요