>  기사  >  백엔드 개발  >  C++에서 메모리 누수 감지

C++에서 메모리 누수 감지

巴扎黑
巴扎黑원래의
2016-11-30 11:24:501184검색

먼저 프로그램에 메모리 누수가 있는지 확인하고, 메모리 누수가 있는 코드 줄을 찾아서 문제를 해결해야 합니다.

물론 가장 쉬운 방법은 잘 알려져 있고 매우 강력한 BoundsCheck와 같은 전문적인 탐지 도구를 사용하는 것입니다. C++를 개발하는 사람이라면 누구나 이 도구 없이는 할 수 없을 것입니다. 또한
먼저 프로그램에 메모리 누수가 있는지 확인한 다음 어떤 코드 줄에 메모리 누수가 있는지 찾아 문제를 해결할 수 있습니다.

물론 가장 쉬운 방법은 잘 알려져 있고 매우 강력한 BoundsCheck와 같은 전문적인 탐지 도구를 사용하는 것입니다. C++를 개발하는 사람이라면 누구나 이 도구 없이는 할 수 없을 것입니다. 또한 별도의 도구를 사용하지 않고 메모리 누수 모니터링을 직접 구현하는데 이는 다음 두 가지 상황으로 나눌 수 있습니다.

1. MFC에서 메모리 누수를 감지하는 경우

MFC 프로그램을 사용하고 있다면 매우 간단합니다. 기본적으로 메모리 누수 감지 기능이 있습니다.

우리는 VS2005를 사용하여 MFC 대화 상자 프로그램을 생성했고 이것이 자동으로 메모리 누수를 감지할 수 있다는 것을 발견했습니다. 주의 깊게 관찰한 결과, 각 CPP 파일에 다음과 같은 내용이 있다는 것을 발견했습니다. 다음 코드는 다음과 같습니다.
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

DEBUG_NEW 이 매크로는 afx.h 파일에 정의되어 있어 메모리 누수를 찾는 데 도움이 됩니다.

위 코드가 포함된 cpp 파일에 메모리를 할당한 후에도 메모리가 삭제되지 않으면 프로그램이 중지되면 Visual Studio의 출력 창에 다음 정보가 표시됩니다.
메모리 누수가 감지되었습니다!
객체 덤프 ->
d:codemfctestmfctest.cpp(80) : 0x003AF170의 {157} 일반 블록, 길이 4바이트.
데이터: < 완료됩니다.

출력 창에서 굵은 선을 두 번 클릭하면 IDE가 파일을 열고 메모리 누수가 발생한 위치를 쉽게 확인할 수 있습니다.

2. 순수 C++ 프로그램에서 메모리 누수 감지

Visual Studio로 만든 Win32 콘솔 응용 프로그램과 Win32 프로젝트 프로젝트를 시도했지만 메모리 누수를 감지할 수 없었습니다.

다음은 프로그램의 메모리 누수 감지 메커니즘을 구축하는 단계별 프로세스입니다.

먼저, C 런타임 라이브러리의 디버그 버전은 프로그램 디버깅을 더 쉽게 할 수 있도록 다양한 감지 기능을 제공한다는 점을 알아야 합니다. MSDN에는 Debug Routines라는 특별한 장이 있습니다. 먼저 내용을 읽어보시기 바랍니다.

몇 가지 중요한 기능을 사용할 것입니다. 가장 중요한 것은 _CrtDumpMemoryLeaks입니다. MSDN의 도움말을 직접 확인하세요. 이 기능을 사용하려면 헤더 파일 crtdbg.h를 포함해야 합니다

이 기능은 디버그 버전에서만 유용합니다. 디버거에서 프로그램을 실행할 때 _CrtDumpMemoryLeaks는 "출력"에 메모리 누수 정보를 표시합니다. window .다음과 같이 테스트할 코드를 작성하세요.

메모리 누수 버전 1 감지:

#include "stdafx.h"
#include
int _tmain(int argc, _TCHAR* argv[])
{
int* p = new int;
_CrtDumpMemoryLeaks;
return 0;
}

실행 후, 출력(출력) 창에 다음 정보가 표시됩니다.

메모리 누수가 감지되었습니다!
덤핑 개체 ->
{112} 0x003AA770의 일반 블록, 4바이트 길이.
데이터: < ; 00 00 00 00
객체 덤프가 완료되었습니다.

그러나 이는 프로그램에 메모리 누수가 있음을 알려주는 것일 뿐, 어디서 누출되었는지 한눈에 파악하기 어렵습니다.

메모리 누수 감지 버전 2 보기:

#include "stdafx.h"

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#새 DEBUG_CLIENTBLOCK 정의
#endif
int _tmain(int argc, _TCHAR* argv[])
{
int* p = new int;
_CrtDumpMemoryLeaks;
return 0;
}

The 프로그램은 여러 매크로를 정의하고 디버그 버전에서 매크로를 사용하여 new를 호출할 때 파일 이름과 코드 줄을 기록합니다.

감지된 메모리 누수!

객체 덤프 ->
d:codeconsoletestconsoletest.cpp(21): 0x003A38B0의 {112} 클라이언트 블록, 하위 유형 0, 길이 4바이트.
데이터: < >객체 덤프 완료.

ㅋㅋㅋ MFC 프로그램과 같은 효과인데 잠깐만요. 다음 코드를 살펴보세요:

int _tmain(int argc, _TCHAR* argv[])

{

int* p = new int;
_CrtDumpMemoryLeaks;
delete p ;
return 0;
}

실행 후 포인터를 삭제했지만 여전히 메모리 누수를 보고한 것을 확인할 수 있습니다. 따라서 new가 호출될 때마다 호출이 배열 레코드를 갖는 것과 유사하게 프로그램 내부에 기록된다는 것을 상상할 수 있습니다. 삭제되면 배열에서 삭제되고 _CrtDumpMemoryLeaks는 현재 상태를 인쇄합니다. 배열의 . <… 여러 곳에서 호출됩니다.

더 나아가 프로그램이 클래스 소멸자에 있는 포인터를 삭제한다면 어떻게 될까요? 예:

#include "stdafx.h"
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
# _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
class Test
{
public:
Test 정의 { _p = 새 int; }
~테스트 { 삭제 _p; }
int* _p;
};
int _tmain(int argc, _TCHAR* argv[])
{
int* p = new int;
delete p;
Test t;
_CrtDumpMemoryLeaks;
return 0;
}

프로그램이 실행될 때 소멸자가 종료되는 것을 볼 수 있습니다. 종료 호출될 때만 호출됩니다. 분명히 메모리 누수는 없지만 이 쓰기 방식은 여전히 ​​보고됩니다.

개선 방법, 메모리 누수 감지 버전 3 참조:

#include "stdafx.h"
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#새 DEBUG_CLIENTBLOCK 정의
# endif
class Test
{
public:
Test { _p = new int; }
~Test { delete _p;
int* _p;
};
int _tmain(int argc, _TCHAR* argv[])
{
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
int* p = new int;
p 삭제;
t 테스트;
return 0;
}

_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ) 이 문은 프로그램이 종료될 때 자동으로 _CrtDumpMemoryLeaks를 호출합니다. _CRTDBG_ALLOC_MEM_DF와 _CRTDBG_LEAK_CHECK_DF를 동시에 설정해야 합니다.

이렇게 해서 이번 버전도 MFC와 같은 효과를 얻었으나 출력창에 정보만 출력하기 때문에 이것만으로는 부족하다고 생각합니다. 개발자에게 매우 중요합니다. 알림은 아직 명확하지 않으며 종종 놓치는 경우가 많습니다. 게다가 많은 사람들이 메모리 누수를 발견하더라도 복구가 어렵고 프로그램의 외부 성능에 심각한 영향을 미치지 않습니다. 개발자가 메모리 누수를 사전에 해결하려면 어떻게 해야 합니까? 한때 누군가와 협력하여 프로그램을 작성했던 기억이 납니다. 내 함수 매개변수에는 요구사항이 있어서 비워둘 수 없었지만 다른 사람들은 항상 함수 시작 부분에서 함수 매개변수를 확인하고 이를 어설션할 수밖에 없었습니다. 이런 식으로 프로그램이 실행 중일 때 항상 주장이 나타나서 프로그램 디버깅이 너무 스트레스를 받았고 결국 다른 프로그래머들이 짜증을 내고 문제를 해결했으며 입력 매개 변수가 정확했습니다. 그래서 프로그래머가 주도적으로 뭔가를 하게 하려면 먼저 그렇게 하면 자신의 부담이 줄어들고 작업이 더 쉬워진다는 느낌을 갖게 해야 한다고 생각합니다. 하하, 프로그램이 종료될 때 메모리 누수가 감지되면 프로그램이 메시지를 표시합니다.

메모리 누수 감지 버전 4 보기:

#include "stdafx.h"
#include
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK 새로운 ( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
# new DEBUG_CLIENTBLOCK
#endif
void Exit
{
int i = _CrtDumpMemoryLeaks;
assert( i == 0);
}
int _tmain(int argc, _TCHAR Define * argv[])
{
atexit(Exit);
int* p = new int;
return 0;
}

이 버전은 다음과 같은 경우에 실행됩니다. 프로그램이 종료됩니다. 메모리 누수가 있는지 확인하세요.

atexit(Exit); 프로그램이 종료될 때 실행되도록 프롬프트 대화 상자가 나타납니다. Exit 함수에서 메모리 누수가 있는 경우 _CrtDumpMemoryLeaks는 0이 아닌 값을 반환하고 이를 어설션합니다.

이 버전을 사용할 준비가 되었습니다. 하지만 코드에서 모든 메모리 누수를 정확하게 감지하려면 new를 사용하여 코드의 #define...을 모든 파일에 복사해야 하기 때문에 여전히 몇 가지 개선이 가능합니다. 파일별로 너무 많은 코드를 복사하는 것은 불가능하므로 추출하여 파일에 넣어보겠습니다. 예를 들어, 파일 내용은 다음과 같습니다.

#pragma one afeen #ifdef _debug #include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

그런 다음 공통 파일에 KDetectMemoryLeak.h를 포함시킵니다. 예를 들어 VS로 빌드된 프로젝트는 이를 stdafx.h에 포함합니다. 또는 기본적으로 모든 파일에서 사용되는 일부 공통 코드가 포함된 Common.h 파일을 직접 만들었습니다.



성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.