통합검색
· 마을서비스란?  · 포럼마을  · 일반마을  · 테마마을  · 마을랭킹  · 활동왕
· 덱스퍼트란?  · TECBOX   · PRSBOX   · 이용안내  
· DEXT제품군  · 솔루션베이  · S/W & ESD 컴포넌트
· 프로그램베이
· LiveSeminar  · LiveConference
Visual C++ 포럼마을 입니다.
  마을등급 Visual C++   이 마을은 포럼마을 입니다이 마을은 자유가입제 마을 입니다 마을소개 페이지로 이동 전입신청
마을촌장촌장 나성훈 주민 34022 since 2006-12-29
우리마을 공지사항
질문&답변
강좌&팁
자유게시판
자료실
앨범
개인게시판
마을 게시판
등록된 마을 게시판이
없습니다.
랑데브 게시판
칼럼 게시판
개발자 고충상담
Dev Talk
자유토론방
벼룩시장
재나미 우스개
구인/프로젝트 정보
사람인 채용 게시판
  고객지원 게시판
마이 데브피아
 나의 e-Money 내역
 활동왕 My Page
 스크랩한 게시글보기
 쪽지관리
 주소록관리

 강좌&팁
 메모리 누수 없는 코드 만들기  | VC++ 일반 2006-03-31 오후 2:01:12
 pbell  pbell님께 메시지 보내기pbell님을 내 주소록에 추가합니다.pbell님의 개인게시판 가기 번호: 7288  / 읽음:11,360

 Visual Studio 에서 개발할 경우 메모리 누수를 확인할려면

디버그 모드에서 F5 (Ctrl+F5 아님) 로 프로그램을 실행하면 되는건 아시죠?

이때 C++ 의 경우는 new 를 사용하고 메모리 반환을 하지 않는경우 해당 위치를 output 창에 보여줍니다.

예를 들어 아래의 코드로 메모리 할당후 어디에서도 반환하지 않았다고 가정해봅시다.

             char *pszTest = new char[100] ;

F5 로 프로그램 실행후 종료하면 Debug 출력창에 아래와 같이 나옵니다.

Detected memory leaks!

Dumping objects ->

D:\Project\MemoryTest.cpp(60) : {73} normal block at 0x00374E58, 100 bytes long.

 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

Object dump complete.

 

F4 또는 위의 파일경로명을 더블클릭 하면 해당 위치 소스코드의 포커스를 이동해주기 때문에

메모리누수를 해결하는데 아주 편리합니다.

이렇게 가능한 이유는 비쥬얼스튜디오에서 프로젝트 생성시 자동으로 추가된 아래의 구문 때문입니다

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

보시면 아시겠지만 new 라는 놈을 DEBUG_NEW 로 다시 정의하였습니다.

실제 디버그에선  new 를 사용해도, DEBUG_NEW 가 실행하게 되는것입니다.

그렇다면, DEBUG_NEW 의 정체가 뭘까요?

 

DEBUG_NEW 가 정의되어있는 소스코드를 가보겠습니다.

DEBUG_NEW <AFX.H> 에 정의되어 있고, 내용은 아래와 같습니다.

#define DEBUG_NEW new(THIS_FILE, __LINE__)

오호라~ new 가 연산자 오버로딩 되어 있는게 확인됩니다.

일반적으로 우리가 생각하는 new 는 인자로 할당할 크기만 주게 되어 있습니다.

하지만, 위의 구문을 보면 해당 위치의 파일명과 라인수를 지정하게 되어 있군요.

다시말해, new 를 사용할때마다 사용된 곳의 파일 경로와 해당 라인수를 메모리에 함께 등록하는 것입니다.

 

결국 해당 메모리가 제거되지 않았을땐, 메모리에 기록해둔 파일경로와 라인수를 참조해서 디버그 출력창에 뿌려주고

이를 식별자로 사용하여 이동하기 쉽게 해주고 있습니다.

여기까지는 비쥬얼 스튜디오가 자동으로 해주기 때문에 크게 신경쓸 일이 없었습니다.

하지만, 문제는 C 코드일 경우입니다.

비쥬얼스튜디오는 불행하게도 C 코드로 된 프로젝트를 생성하는 마법사가 없습니다.

그러다보니 자동으로 생성해주는 메모리 누수 매크로도 제공하질 않습니다.

실제 C 코드에서 사용하는 malloc 을 사용해서 메모리 해제 하지 않고 결과를 보겠습니다.

char *pszTest2 = (char*)malloc(100*sizeof(char)) ;

위코드를 수행후 종료하면 디버그출력창에 아래와 같이 나옵니다.

etected memory leaks!

Dumping objects ->

{73} normal block at 0x00374E58, 100 bytes long.

 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

Object dump complete.

도대체 어떻게 하라는건지

더블클릭해도 아무 반응도 없고, 어디서 메모리 해제가 일어났는지 아무런 정보도 주질 못하고 있습니다.

 

그렇다고 포기할순 없죠.

C++ new에 사용했던 방식대로 C malloc 에도 똑같이 해주면 될 것 같습니다.

malloc 할때 현재 파일경로와 라인수를 식별자로 함께 등록해주면 되겠군요.

그렇다면 이러한 매크로(DEBUG_NEW와 같은)를 직접 만들어야 할까요?

 

친절하게도 비쥬얼스튜디오 헤더파일에 미리 다 만들어 놨더군요.

우선 결과 코드를 보겠습니다.

#ifdef _DEBUG

#include <crtdbg.h>

#ifdef malloc

#undef malloc

#endif

#define malloc(s) (_malloc_dbg( s, _NORMAL_BLOCK, __FILE__, __LINE__ ))

#endif

 

new 를 사용할 때 처럼, malloc 을 다시 다른 함수를 사용하게 정의하였습니다.

위 코드를 C 소스코드의 상단에 위치시킵니다.

그런후 다시 아까의 코드를 수행후 종료하면 친절한 디버그 출력창으로 바뀐걸 볼 수 있습니다.

Detected memory leaks!

Dumping objects ->

D:\Project\MemoryTest.c (68) : {73} normal block at 0x00374E58, 100 bytes long.

 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD

Object dump complete.

 

위 매크로를 보시면 _malloc_dgb 라는 매크로가 보입니다.

우린 그저 가져다 쓴것에 불과하군요.

<crtdbg.h> 를 열어보시면 메모리 관련 함수인  malloc, calloc, realloc, expand, free, msize 에 대한

디버그용 매크로가 정의되어 있는걸 보실 수 있습니다.

그렇다면 _malloc_dgb 에서 사용된 인자들의 의미가 과연 무얼까요?

s 는 실제 할당할 크기(사이즈) 입니다.

_NORMAL_BLOCK 는 시스템에서 메모리를 할당할 때 사용되는 블록의 기본 단위 크기 입니다.

 __FILE__ 은 현재 코드의 전체 경로명입니다.

__LINE__ 은 현재 코드의 수행중인 라인수 입니다.

다시,  crtdbg.h 를 보시면 free 라는 놈도 디버그용이 있습니다.

이왕 하는거 위에서 정의된 모든 메모리 관련 함수에 대해서 디버그용으로 변경해 봅시다.

#ifdef _DEBUG

#include <crtdbg.h>

           #ifdef malloc

           #undef malloc

           #endif

           #define malloc(s) (_malloc_dbg(s, _NORMAL_BLOCK, __FILE__, __LINE__ ))

           #ifdef calloc

           #undef calloc

           #endif

           #define calloc(c, s) (_calloc_dbg(c, s, _NORMAL_BLOCK, __FILE__, __LINE__ ))

           #ifdef realloc

           #undef realloc

           #endif

           #define realloc(p, s) (_realloc_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__ ))

           #ifdef _expand

           #undef _expand

           #endif

           #define _expand(p, s) (_expand_dbg(p, s, _NORMAL_BLOCK, __FILE__, __LINE__  ))

           #ifdef free

           #undef free

           #endif

           #define free(p) (_free_dbg(p, _NORMAL_BLOCK))

           #ifdef _msize

           #undef _msize

           #endif

           #define _msize(p) (_msize_dbg(p, _NORMAL_BLOCK))

#endif

 

이제 메모리누수 안녕~~~

[코멘트] 놀람
2006-03-31 17:22
 redqa01  redqa01님께 메시지 보내기redqa01님을 내 주소록에 추가합니다.redqa01님의 개인게시판 가기 
유용한 정보 정말 감사드립니다 ^^

제가 그코드를 stdAfx.h 헤더파일에 긁어 붙였는데 다음과 같은 네개의 에러가 뜹니다......

_CRTIMP void * __cdecl calloc(size_t, size_t);

위라인에서 error C2059: syntax error : '('

이러한 에러가 발생하네요

긁어 붙인 위치는 다음과 같습니다

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#if !defined(AFX_STDAFX_H__8C615AF8_7143_4760_9C3E_4242E7BEA45A__INCLUDED_)
#define AFX_STDAFX_H__8C615AF8_7143_4760_9C3E_4242E7BEA45A__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers

#ifdef _DEBUG
#include
.......... <<= 이위치
#endif

#include
#include "HandleFile.h"
#include

using namespace std;


#define SAFE_MEM_FREE( p ) if( p ) {free(p); p = NULL;}
#define SAFE_DELETE( p ) if( p ) {delete p; p = NULL;}
//Global Function
void MenuDisplay();
int MenuSelect();

//Global Variable
extern bool g_bProgramEnd;
// TODO: reference additional headers your program requires here

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_STDAFX_H__8C615AF8_7143_4760_9C3E_4242E7BEA45A__INCLUDED_)
저장 취소
[코멘트] 좋음
2006-03-31 17:30
 pbell  pbell님께 메시지 보내기pbell님을 내 주소록에 추가합니다.pbell님의 개인게시판 가기 
헤더파일에 선언하는것은 별로 좋지 못합니다.
소스파일에서 모든 헤더파일을 인클루드 한 후에 본 매크로가 들어가야 합니다.
비쥬얼스튜디오에서도 프로젝트 생성해주고 굳이 cpp 마다 DEBUG_NEW 를 사용하게 해준 이유를 생각해 보시면 될것 같군요.
불편하시더라도 그게 가장 안전한 방법입니다.

긁어붙인곳을 c 나 cpp 파일로 옮겨서 해보세요.
저장 취소
[코멘트] 좋음
2006-04-02 22:05
 junyoungky  junyoungky님께 메시지 보내기junyoungky님을 내 주소록에 추가합니다.junyoungky님의 개인게시판 가기 
유용한 내용 감사합니다.

malloc 에 의한 누수위치를 확인 할 수가 없었는데, 이글을 보니 금방 이해가 가는군요.
저장 취소
[코멘트] 좋음
2006-04-03 20:13
 redqa01  redqa01님께 메시지 보내기redqa01님을 내 주소록에 추가합니다.redqa01님의 개인게시판 가기 
허걱....

왜 에러가 뜰까요???

cpp파일에 디파인하고

다음과 같이 썼습니다

char* Buffer;
Buffer = (char*)malloc(sizeof(char) * MAX); <= 이 라인에서 's'가 선언되지 않은 identifier라고 컴파일에러가 나네요...

제가 뭘 잘못한거죠??
저장 취소
[코멘트] 좋음
2006-04-04 09:25
 pbell  pbell님께 메시지 보내기pbell님을 내 주소록에 추가합니다.pbell님의 개인게시판 가기 
지송~ 공백이 들어가 있었군요. ^^
편집 툴이 익숙치 않아서..
공백제거 수정했습니다.
저장 취소
[코멘트] 좋음
2006-04-06 15:40
 staroot  staroot님께 메시지 보내기staroot님을 내 주소록에 추가합니다.staroot님의 개인게시판 가기 
오 감사 !!!
덕분에 머리 아픈거 하나 해결 하는 군요 ^^
저장 취소
코멘트쓰기
  좋음   놀람   궁금   화남   슬픔   최고   침묵   시무룩   부끄럼   난감
* 코멘트는 500자 이내(띄어쓰기 포함)로 적어주세요.
목록 보기   지금 보고 계시는 글을 회원님의 my Mblog >> 스크랩에 넣어두고 다음에 바로 보실 수 있습니다.  
회사소개  |   개인정보취급방침  |  제휴문의  |   광고문의  |   E-Mail 무단수집거부  |   고객지원  |   이용안내  |   세금계산서
사업자등록번호 안내: 220-81-90008 / 통신판매업신고번호 제 2017-서울구로-0055호 / 대표: 홍영준, 서민호
08390, 서울시 구로구 디지털로32길 30, 1211호 / TEL. 02_6719_6200 / FAX. 02-6499-1910
Copyright ⓒ (주) 데브피아. All rights reserved.