장시간 프로그램 실행시 메모리가 증가하는 경우, 자원 해제를 빼먹은 부분을 찾아주는 유용한 툴 중 하나인,

"Visual Leak Detector for Visual C++ 2008/2010/2012/2013"라는 유용한 라이브러리를 소개합니다.


설치 후 간단하게 프로젝트에 헤더파일 추가와 경로설정만하면 끝!


1. 다운로드 & 설치




2. C++ 프로젝트에 VLD 경로 추가


Visual C++ 프로젝트 속성을 클릭하여 VC++ 디렉터리의 포함/라이브러리 디렉터리에 VLD의 경로를 추가합니다.


1) 포함 디렉터리 추가

ex) "C:\Program Files (x86)\Visual Leak Detector\include"



2) 라이브러리 디렉터리 추가

ex) "C:\Program Files (x86)\Visual Leak Detector\lib\Win32" (개발하는 프로그램이 32bit인 경우)




3. VLD 헤더파일 추가


VLD를 사용하기 위한 헤더파일을 소스에 추가합니다.



4. 메모리 누수 체크하기


간단한 샘플 코드를 실행하여 종료시킨 후의 DEBUG 로그를 확인합니다.

디버그로그에 보면 파일의 경로와 함께 "memoryleaktest.cpp (6)"이라고 출력이되었고, 

해당 파일의 6번째 라인을 보면 누수된 코드를 확인 할 수 있습니다.


* 메모리 누수가 체크된 경우




* 메모리 누수가 없다고 체크된 경우


메모리 누수가 없는 경우는 아래와 같이 출력됩니다.

Visual Leak Detector Version 2.3 installed.

    Outputting the report to the debugger and to F:\Project\Test\MemLeakTestCpp\memory_leak_report.txt

No memory leaks detected.

Visual Leak Detector is now exiting.



* 샘플 코드



◆ VLD 출력 설정하기


출력 데이터를 파일로, callstack level 설정 등을 변경하고 싶다면 vld.ini 파일을 수정합니다.

(설치된 경로에 위치)


* 출력 데이터 경로 설정하기 : 파일 및 debugger

1) ReportTo 값을 Both로 변경하여 debugger와 파일로 동시 출력하게 설정

2) 파일 확인





출처: http://dg087.tistory.com/9 []

안녕하세요 푸민입니다.

 

UML 기호를 정리합니다~

 

1. Class

- 클래스를 나타냅니다.

 

- 기호

 

- 소스

class ClassName {

public Object Attribute1;

protected int Attribute2;

private String Attribute3;

 

public void Operation1(){

...

}

protected int Operation2(){

...

}

private String Operation3(String str){

...

}

}

 

 

2. Generalization - 일반화, 상속

- 상속을 받은 객체를 표시한다.

 

- 기호

 

 

- 소스

class Parents{

...

}

class Child extends Parents{

...

}

 

 

3. Realization - 실체화, 구현

- 인터페이스를 구현한다.

 

- 기호

 

- 소스

interface Interface{

...

}

class Class implements Interface{

...

}

 

 

4. Dependency - 의존, 파라미터, 리턴 값 등

- 의존적인 성격을 가지고 있는 파라미터, 리턴값 등에 사용할 경우 표시한다. Contract에서 변화가 생기면 Phone에서 코드의 변화를 줘야한다.

 

- 기호

 

- 소스

class Contact{

...

}

class Phone{

public void call(Contact contact){

...

}

}

 

 

5. Association - 연관

- 관계를 나타낼때 사용

 

- 기호

 

- 소스

class AssociationClass{

public void test(){

Constant.STR;

}

}

 

 

6. Directed Association - 직접 연관

- 직접적으로 해당 클래스를 변수로서 사용함, person 객체가 있어도 되고 없어도 된다.

 

- 기호

 

- 소스

class Person{

...

}

class Car{

private Person person;

}

 

 

7. Aggregation - 집합, 집합 연관

- 해당 클래스를 직접 생성하지는 않고 인스턴스를 받아서 사용한다.

 

- 기호

 

- 소스

class Fuel{

...

}

class Car{

private Fuel fuel;

 

public Car(Fuel fuel){

this.fuel = fuel;

}

}

 

 

8. Composition - 합성, 합성 연관

- 클래스를 직접 인스턴스로 생성하여 사용한다.

 

- 기호

 

- 소스

class Engine{

...

}

class Car{

private Engine mEngine;

public Car(){

mEngine = new Engine();

}

}

 

 

9. InnerClass - 이너 클래스

- 클래스 내부에 클래스를 정의한다.

 

- 기호

- 소스

class Phone{

...

class Contact{

...

}



출처: http://fumin.tistory.com/45 [푸민의 블로그]

- 클래스(구조체)의 바이트 패딩 -
멤버 변수를 메모리에서 CPU 레지스터로 한번에 읽을 수 있도록
CPU 레지스터의 읽기 블록에 맞춰 정렬하는 컴파일러의 최적화 작업
컴파일러가 패딩을 하지 않아 레지스터가 읽는 블록의 경계에 걸쳐 멤버 변수가 생긴다면
메모리를 읽을 때 두개의 블록을 읽어는 문제가 발생
CPU 레지스터는
32비트 운영체제일때 4바이트
64비트 운영체제일때 8바이트 단위로 메모리를 읽는다

구조체를 4바이트 단위로 끊어주는것을 "바이트 패딩" 이라고 한다.
 

구조체는 메모리에 어떤 식으로 저장될까
다음과 같은 소스를 보자.
 
  1. #include <stdio.h>   
  2.   
  3. typedef struct _TEST{   
  4.     char cData;   
  5.     short sData;   
  6.     int iData;   
  7. }TEST;   
  8.   
  9. int main()   
  10. {   
  11.     TEST TData={0,};   
  12.   
  13.     printf("cData size : %d\n"sizeof(TData.cData));   
  14.     printf("sData size : %d\n"sizeof(TData.sData));   
  15.     printf("iData size : %d\n"sizeof(TData.iData));   
  16.     printf("TData size : %d\n"sizeof(TData));   
  17.        
  18.     return 0;   
  19. }  


TEST 구조체 변수인 TData는 char형 데이터(1byte), short형 데이터(2byte), int형 데이터(4byte)를 가지고 있으므로 1+2+4=7byte의 크기를 가질 것 처럼 보인다. 하지만 이 소스를 컴파일하고 실행을 해보면 다음과 같은 결과가  나온다.

 

분명히 cData(1) + sData(2) + iData(4) = 7임에도 불고하고 TData의 크기는 8바이트라고 하니 참 이상한 일이다.

이는 현재 우리가 쓰는 32비트 컴퓨터에서 32비트 컴파일러를 사용하였기 때문에 32비트 즉, 4바이트로 데이터를 처리하는 것에 가장 최적화되어 있기 때문에 데이터를 4바이트 공간으로 저장하기 때문이다.

이 TData란 구조체는 8바이트에 다음과 같이 저장되어 있다.

cData
??
sData
sData
iData
iData
iData
iData

cData를 저장하고, 4바이트중에 3바이트가 남아있기 때문에 sData를 3바이트 중에 2바이트의 공간에 저장하고,
iData를 저장하려 하니 1바이트밖에 남아있지 않기 때문에 4바이트의 공간을 따로 만들어 저장하게 되는 것이다.

그럼 이제 위의 소스에서 변수 선언의 순서를 한 번 바꿔 보자.

 
  1. typedef struct _TEST{   
  2.     char cData;   
  3.     int iData;   
  4.     short sData;   
  5. }TEST;  

 
변수 선언의 순서를 바꿨을 뿐인데 신기하게도 같은 구조체의 크기가 8에서 12로 늘어나버렸다.
이 TData 구조체 변수는 다음과 같이 저장되어 있을 것이다.

cData
(1byte)
empty
(3byte)
sData
(2byte)
empty
(2byte)
iData
(4byte)

이처럼 컴파일러는 4바이트에 맞춰서 데이터를 저장하는 것을 볼 수 있다. 이것을 막으려면 어떻게 해야할까.

이것을 해결하려면 #pragma pack() 이라는 전처리어를 사용하면 된다.
구조체 하나를 더 추가한 다음 소스를 보자.

 
  1. #include <stdio.h>   
  2.   
  3. typedef struct _TEST{   
  4.     char cData;   
  5.     int iData;   
  6.     short sData;   
  7. }TEST;   
  8.   
  9. #pragma pack(1)   
  10. typedef struct _TEST2{   
  11.     char cData;   
  12.     int iData;   
  13.     short sData;   
  14. }TEST2;   
  15.   
  16. int main()   
  17. {   
  18.     TEST TData={0,};   
  19.     TEST2 TData2={0,};   
  20.   
  21.     printf("TData size : %d\n"sizeof(TData));   
  22.     printf("TData2 size : %d\n"sizeof(TData2));   
  23.        
  24.     return 0;   
  25. }  

 
#pragma pack(1)에서 1은 1바이트 단위로 저장하겠다는 것이다. 따라서 TData와 TData2의 내용물은 같으나 크기는 다른 것을 확인할 수 있다.

 그렇다면, 왜 모두 1바이트로 해서 메모리의 낭비가 없도록 하지 않는 것일까?
 그것은, 아까도 이야기하였듯이 32비트 CPU에서는 4바이트(32비트)의 단위로 데이터를 처리하는 것이 가장 빠르게 때문이다. 즉, #pragma pack(1) 이라고 선언해놓고 원래대로 돌려놓지 않는다면 속도저하의 문제가 생길 수 있다.
 따라서, 위의 소스에서 구조체 선언이 끝나는 부분에 #pragma pack(4)라고 선언해주어 할 것이다.

 하지만, 여기에도 문제가 있다.
 만약, 이 소스를 32비트의 PC가 아닌 다른 CPU가 장착된 장비에서 컴파일하게 된다면 어떻게 될 것인가. 예를 들면 임베디드 시스템 같은 8~16비트 CPU에서 말이다.
 소스를 일일히 찾아서 CPU에 맞게 고쳐주고 다시 컴파일해야 되는 불편함과 어려움이 생기게 된다.

 이럴때를 위해서 좀 더 우아하게 쓰는 코드가 있다.

 
  1. #pragma pack(push, 1)   
  2. typedef struct _TEST2{   
  3.     char cData;   
  4.     int iData;   
  5.     short sData;   
  6. }TEST2;   
  7. #pragma pack(pop)  


 기존의 바이트를 스택에 push하고 1바이트 단위로 처리한다음 끝나는 부분에 원래의 바이트 단위를 pop해주는 코드이다. 보통은 이렇게 사용하면 되겠다.


 

아래와 같은 코드를 사용하면 구조체 크기는 1바이트가된다.

  1. #pragma pack(push, 1)   
  2. typedef struct DATA{   
  3.     char cData;      
  4. }DATA;   
  5. #pragma pack(pop)  



출처: http://javawoo.tistory.com/30 []

+ Recent posts