Jump to content
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr ×
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr

[튜토리얼 번역] 딜리커 (Deleaker)를 사용하여 "델파이" 에서 메모리 누수를 찾는 방법


Recommended Posts

Deleaker 도움말 중 델파이에서 사용하는 방법을 번역했습니다.

델파이 에서 메모리 누수를 찾는 방법

이 튜토리얼은 델파이(Delphi)로 작성된 애플리케이션에서 메모리 누수와 기타 리소스 누출을 감지하는 방법을 설명한다.

딜리커(deleaker)는 독립형 애플리케이션 또는 RAD 스튜디오에 플러그인으로 실행할 수 있다. 예를 들어 RAD 스튜디오가 없는 곳에서는 Deleaker를 독립형으로 실행할 수도 있어서 편하다.

Deleaker를 RAD 스튜디오에서 플러그인으로 실행하면, 개발자가 RAD 스튜디오를 떠나지 않고 바로 누출을 검색할 수 있고, 발생 가능한 오류의 근원으로 더 빠르게 이동할 수 있다.

Deleaker를 RAD 스튜디오에 설치하면, RAD 스튜디오의 메인 메뉴Deleaker 항목이 새로 추가된다.
deleaker_menu_rad_studio.gif
그림1. 델파이에 들어간 Deleaker 메뉴

Deleaker 창을 열려면, 메인 메뉴 > Deleaker > Deleaker Window를 클릭한다.
deleaker_window.png
그림2. 델파이에서 표시되는 Deleaker 창

메모리 누수 추가

폼 하나에 버튼 하나만 있는 간단한 애플리케이션을 만든다. 이 버튼을 클릭하면 메모리 할당과 오브젝트 생성이 되도록 한다.

procedure TForm1.Button1Click(Sender: TObject);
var
  p: Pointer;
  StringList: TStringList;
begin
  GetMem(p, 42);
  StringList := TStringList.Create;
end;

프로젝트 설정

누출에 대한 정보를 가장 신뢰할 수 있게 그리고 완벽하게 얻으려면 프로젝트 옵션을 설정해야 한다.

디버그 정보 활성화

가장 먼저, 컴파일러와 링커가 디버그 정보를 생성하도록 지정해야 한다. Deleaker는 이 정보에 따라 소스 코드가 있는 파일과 이에 대응하는 콜 스택 상의 주소를 연결할 수 있다.

컴파일러의 옵션: 디버그 정보를 생성하려면, 메인 메뉴 > Project > Options를 클릭하면 표시되는 프로젝트 옵션 화면에서, Building > Delphi Compiler > Compiling 항목을 선택한 후 Code generation > Debug information 항목에서 Debug information을 선택한다.

링커의 옵션: 디버그 정보를 생성하려면, 메인 메뉴 > Project > Options를 클릭하면 표시되는 프로젝트 옵션 화면에서, Building > Delphi Compiler > Linking 항목을 선택한 후 Debug information 항목에서 True를 선택한다.
enable_debug_information.png
그림3. 델파이에서 컴파일러와 링커가 디버그 정보를 생성하도록 설정하기

만약 명령줄을 사용하여 프로젝트를 빌드하는 경우,  -V 옵션을 주면 컴파일러에서 디버그 정보를 생성한다.

스택 ( Stack ) 프레임 생성

컴파일러가 스택 프레임을 생성하도록 하는 것이 좋다.

Deleaker는 스택 프레임이 없이 빌드된 경우에도 어떤 코드와도 작업을 할 수 있다. 하지만, 만약 코드가 스택 프레임을 사용하여 컴파일되면 콜 스택 관련 정보의 완성도가 더 높다.

스택 프레임을 활성화하려면, 메인 메뉴 > Project > Options를 클릭하면 표시되는 프로젝트 옵션 화면에서, Building > Delphi Compiler > Compiling 항목을 선택한 후 Code generation > Stack frames 항목에서 True를 선택한다.
enable_stack_frames.png
그림4. 델파이에서 스택 프레임을 활성화하기

만약 명령줄을 사용하여 프로젝트를 빌드하는 경우,  -$W+ 옵션을 주어야 스택 프레임을 생성한다.

최적화 비활성화하기

누수에 대한 보다 완전하고 정확한 정보를 얻으려면 최적화를 비활성화 한다. 메인 메뉴 > Project > Options를 클릭하면 표시되는 프로젝트 옵션 화면에서, Building > Delphi Compiler > Compiling 항목을 선택한 후 Code generation > Optimization 항목에서 False를 선택하고, Debugging > Use debug .dcus 항목에서 True를 선택한다.
disable_optimization.png
그림5. 델파이에서 최적화 비활성화하기

만약 명령줄을 사용하여 프로젝트를 빌드하는 경우,  -$O- 옵션을 주어야 최적화가 비활성화 된다.

스냅샷 찍기

디버깅을 시작하고 버튼을 클릭한다. RAD 스튜디오로 돌아가서 메인 메뉴 > Deleaker > Deleaker Window를 클릭하면 표시되는 Deleaker 창에서 Take Snapshot을 클릭하면, 메모리, 핸들, GDI 리소스, 오브젝트 등 할당된 리소스의 목록을 얻을 수 있다.
take_snapshot.gif
그림6. 스냅샷 찍기

각 리소스 별로 해당 콜 스택을 점검하여 코드의 어느 부분에서 리소스가 할당되었는지를 파악할 수 있다. 해당 소스 파일과 줄을 감지할 수 있는 경우 더블 클릭 (또는 컨텍스트 메뉴)를 사용하면 델파이의 코드 에디터가 열린다.
navigate_source_code.gif
그림7. 누수를 일으키는 소스 코드로 이동하기

델파이 오브젝트 목록 획득하기

Delphi Objects 탭 안의 오브젝트는 클래스 별로 그룹핑되어 있다. 각 클래스 별로 해당 오브젝트가 목록으로 표시된다. 각 오브젝트 별로 콜 스택이 표시된다.
delphi_objects.gif
그림8. 살아있는 델파이 오브젝트 잡기

클래스를 빠르게 찾으려면 Filter by name을 사용한다.  클래스 이름을 타이핑하기 시작하면 해당되는 클래스만 표시된다.
filter_delphi_class.gif
그림9. 클래스 이름으로 델파이 클래스 필터링하기

누수 목록 획득하기

애플리케이션을 나가면, Deleaker가 자동으로 스냅샷을 생성하여 누수 목록 (예: 할당되었으나 해제되지 모든 리소스)을 제공한다. 개발자는 각 할당과 각 오브젝트의 콜 스택을 살펴보고 해당 리소스를 명시적으로 해제 (Free) 할 것인지를 결정할 수 있다.
snapshot_on_exit.gif
그림10. 프로세스를 빠져나가면 스냅샷이 찍힌다.

프로세스가 점점 더 많은 메모리를 소비하는 경우에는 어떻게 할까?

이 경우, 프로세스가 소비하는 메모리가 꾸준하게 증가한다. 핸들(handle) 갯수 또는 GDI 오브젝트의 갯수가 증가하는 다른 경우도 있다.
resource_usage_graph.gif
그림11. Deleaker의 리소스 사용 그래프

누수를 발생시키는 원천을 어떻게 식별하는 지 살펴보자.

예를 들어, 타이머 하나를 추가하여 정기적으로 메모리를 할당한다.

procedure TForm1.Timer1Timer(Sender: TObject);
var
  p: Pointer;
  StringList: TStringList;
begin
  GetMem(p, 42);
  StringList := TStringList.Create;
end;

첫번째: 히트 카운트 (Hit Count)에 신경쓰기

Deleaker는 모든 누수를 해당 콜 스택 별로 그룹핑한다. 동일한 콜 스택을 공유하는 누수의 갯수는 Hit Count 열에 나타난다. 따라서, 만약 메모리가 꾸준하게 동일한 곳에서 할당된다면, Hit Count가 계속 증가하게 된다.

만약 동일한 클래스의 오브젝트가 꾸준하게 생성된다면, Delphi Objects 탭에 있는 Object Count 열의 숫자가 증가하게 된다.

Hit CountObject Count를 내림차순으로 정렬하면 문제되는 코드의 지점을 빠르게 찾을 수 있다.
growing_resource_usage.gif
그림12. 리소스 사용가 꾸준하게 증가하면, Hit CountObject Count를 내림차순으로 정렬하여 빠르게 파악할 수 있다.

두번째: 연속된 스냅샷 사이의 차이점 파악하기

하지만, Hit CountObject Count를 내림차순으로 정렬하기는 "쌓이는" 리소스를 숨길 수 없다. 꾸준하게 누수되는 리소스 만을 보는 또 다른 방법이 있다.

먼저, 기본 스냅샷을 찍는다. 그리고 나서 프로세스가 더 많은 리소스를 할당할 수 있는 시간을 준다. 이렇게 스냅샷 두개가 있으면 우리는 기준 스냅샷이 찍힌 후에 할당된 리소스에만 신경을 쓸 수 있다. 기준 스냅샷을 선택하고 Compare with...를 클릭하고 두번째 스냅샷을 선택한다. 그러면 Deleaker가 이 두개의 스냅샷 사이에 달라진 것만 계산한다.

가끔 스냅샷을 비교한 결과 목록이 비어있다. 이 경우, 모든 필터를 제거하면 모든 할당을 예외없이 볼 수 있다.

결과 목록이 더 깔끔해진다.
compare_snapshots.gif
그림13. 스냅샷 비교하기

필터

Deleaker는 당신의 프로그램이 만든 누수 만을 보여주려고 노력하고 그 외의 것들은 필터링한다.
예를 들어, 시스템 라이브러리 또는 다른 코드에 의해 할당된 메모리 같은 것은 보여주지 않는다. 만약 프로세스에서 할당한 모든 리소스가 보여지면 그 중 어느 것이 당신의 애플리케이션 코드에 해당되는 것인지를 파악하기가 어려울 것이다.

개발자들에게 일부 누수가 숨김 처리되었음을 알려주기 위해 Deleaker는 Filters 버튼 오른쪽에 숨겨진 누수와 표시된 누수의 갯수를 보여준다. 이 버튼을 이용하면 필터를 끄거나 켤 수 있다.
using_filters.gif
그림14. 할당 필터링

필터는 3가지 유형이 있다.

  • Hide leaks with no source code - Deleaker가 소스 코드를 찾지 못하는 누수를 숨긴다. 
  • Hide leaks from excluded modules - 제외된 모듈 즉 Options > Exceptions > Excluded Modules 에 지정된 모듈의 코드에서 만드는 누수를 숨긴다. 디펄트 설정에서는 시스템 라이브러리들이 해당된다.
  • Hide known leaks - 아마 알려진 희망이 없는 누수를 숨긴다: 피하거나 고칠 수 없는 것들이다. 예를 들어 표준 라이브러리에 의한 일회성 메모리 할당 등이 여기에 해당된다. Options > Exceptions > Known Leaks 에서 이런 누수들의 목록을 찾을 수 있다.
이 댓글 링크
다른 사이트에 공유하기

  • Kori changed the title to [튜토리얼 번역] 딜리커 (Deleaker)를 사용하여 "델파이" 에서 메모리 누수를 찾는 방법

이 토의에 참여하세요

지금 바로 의견을 남길 수 있습니다. 그리고 나서 가입해도 됩니다. 이미 회원이라면, 지금 로그인하고 본인 계정으로 의견을 남기세요.

Guest
이 토픽(기고/질문)에 답하기

×   서식있는 텍스트로 붙여넣기.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   이전에 작성한 콘텐츠가 복원되었습니다..   편집창 비우기

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

중요한 정보

이용약관 개인정보보호정책 이용규칙 이 사이트가 더 잘 작동하기 위해 방문자의 컴퓨터에 쿠키가 배치됩니다. 쿠키 설정 변경에서 원하는 설정을 할 수 있습니다. 변경하지 않으면 쿠키를 허용하는 것으로 이해합니다.