C++에서 Crt 의 메모리 누 출 검 측 에 대한 분석 소개

비록 이 개념 은 이미 사람들 로 하여 금 마구 잡 이 로 말 하 게 했 지만,나중에 조회 할 수 있 도록 간단하게 기록 하고 싶다.4567913)주요 원 리 는 Crt 의 메모리 디 버 깅 기능 을 사용 하여 기본 operator new 를 매크로 로 대체 하여 다음 버 전 으로 대체 하 는 것 입 니 다.

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif


int _tmain(int argc, _TCHAR* argv[])
{
    char* p = new char();
    char* pp = new char[10];
    char* ppp = (char*)malloc(10);

    _CrtDumpMemoryLeaks();

    return 0;
}

그러면 Crt 는 이번에 분 배 된 메모리 의 파일 이름과 줄 번호,크기 등 을 기록 하고 마지막 으로 호출 용CrtDumpMemoryLeaks(); 아직 풀 리 지 않 으 면 인쇄 됩 니 다.결 과 는 다음 과 같다.

void *__CRTDECL operator new(
        size_t cb,
        int nBlockUse,
        const char * szFileName,
        int nLine
        )
        _THROW1(_STD bad_alloc)
{
    /* _nh_malloc_dbg already calls _heap_alloc_dbg in a loop and calls _callnewh
       if the allocation fails. If _callnewh returns (very likely because no
       new handlers have been installed by the user), _nh_malloc_dbg returns NULL.
     */
    void *res = _nh_malloc_dbg( cb, 1, nBlockUse, szFileName, nLine );

    RTCCALLBACK(_RTC_Allocate_hook, (res, cb, 0));

    /* if the allocation fails, we throw std::bad_alloc */
    if (res == 0)
    {
        static const std::bad_alloc nomem;
        _RAISE(nomem);
    }

    return res;
}

다음은 주의사항 이다.(1)\#defineCRTDBG_MAP_ALLOC 의 역할 은 이 매크로 를 정의 하지 않 으 면 C 방식 의 malloc 유출 이 기록 되 지 않 습 니 다.
(2)숫자{108}{107}의 역할 은 몇 번 째 분 배 를 나타 내 며CrtSetBreakAlloc 프로그램 이 예 정 된 횟수 로 실 행 될 때 일시 정지 합 니 다.예 를 들 어

Detected memory leaks!
Dumping objects ->
f:\test\memleakchecker\memleakchecker\memleakchecker.cpp(23) : {108} normal block at 0x0003A1A8, 10 bytes long.
 Data: <          > CD CD CD CD CD CD CD CD CD CD
f:\test\memleakchecker\memleakchecker\memleakchecker.cpp(22) : {107} client block at 0x0003A160, subtype 0, 10 bytes long.
 Data: <          > CD CD CD CD CD CD CD CD CD CD
f:\test\memleakchecker\memleakchecker\memleakchecker.cpp(21) : {106} client block at 0x0003A120, subtype 0, 1 bytes long.
 Data: < > 00
Object dump complete.
(3)프로그램 에 여러 개의 출구 가 있 거나 전역 변수 가 있 으 면CrtSetDbgFlag 설정 로 고 는 프로그램 이 종 료 될 때 자동 으로 인쇄 되 어 유출 됩 니 다.예 를 들 어

int _tmain(int argc, _TCHAR* argv[])
{
    _CrtSetBreakAlloc(108);

    char* p = new char();
    char* pp = new char[10];
    char* ppp = (char*)malloc(10);

    _CrtDumpMemoryLeaks();

    return 0;
}

(4)매크로 대체 가 가장 거 친 방식 이라는 것 을 알 고 있 기 때문에 아래 new 대체 매크로 를 모든 Cpp 에 넣 는 것 이 일반적인 헤더 파일 에 넣 는 것 이 아니 라 실제 MFC 도 이렇게 했 습 니 다

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

    char* p = new char();
    char* pp = new char[10];
    char* ppp = (char*)malloc(10);

    return 0;
}

(5)위의 operator new 는 가장 일반적인 new 만 고려 할 수 있 습 니 다.실제로 operator new 는 여러 가지 과부하 방식 이 있 으 며,첫 번 째 매개 변 수 는 크기 를 표시 하 는 것 임 을 확인 해 야 합 니 다.예 를 들 어 아래 placement new 는 컴 파일 에 실 패 했 습 니 다.매크로 대체 후 형식 이 요구 에 부합 되 지 않 기 때문에 CPP 가 표준 이 아 닌 new 를 사용 했다 면 new 검 측 매크로 를 추가 하지 마 십시오.

#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
(6)STL 에 맵 에 있 는 tree 가 placement new 를 사 용 했 기 때문에,  그래서 이렇게 사용 하면 컴 파일 에 실 패 했 습 니 다.

#include <new>

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif


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

    char* p = new char();
    char* pp = new char[10];
    char* ppp = (char*)malloc(10);

    char d;
    char* p1 = new(&d) char('a');

    return 0;
}

\#include를 매크로 정의 앞 에 놓 아야 합 니 다.
(7)만약 당신 이 宏\#define new DEBUG 에 있다 면CLIENTBLOCK 이후 operator new 함 수 를 설명 하거나 정의 하면 매크로 대체 로 컴 파일 에 실 패 했 습 니 다.STL 의 xdebug 파일 은 operator new 함 수 를 설명 하고 있 습 니 다.따라서 new 의 대체 홍 보 를 모든 include 헤더 파일 의 마지막 에 두 고 특히 STL 헤더 파일 뒤에 두 어야 합 니 다.

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

#include <map>

(8)위의 이러한 new 대체 매크로 가 각 CPP 에 분산 되 어 있다 고 생각 하 는 것 이 너무 번거롭다 면 모든 것 을 하나의 유 니 버 설 헤더 파일 에 넣 으 려 면 다음 과 같은 정의 방식 을 참고 하 십시오.

//MyClass.cpp
#include "myclass.h"
#include <map>
#include <algorithm>

#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

MyClass::MyClass()
{
    char* p = new char('a');
}

(9)특정한 독립 함수 가 메모리 유출 이 있 는 지 간단하게 판단 하고 아래 의 방법 으로 할 수 있 습 니 다.

//MemLeakChecker.h
#include <map>
#include <algorithm>
//other STL file

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

(10)사실은 원 리 를 알 게 되 었 습 니 다.C++메모리 유출 검 사 를 스스로 작성 하 는 것 도 어렵 지 않 습 니 다.주로 operator new 와 operator delete 를 다시 불 러 옵 니 다.매번 메모리 할당 상황 을 하나의 맵 에 기록 할 수 있 습 니 다.delete 시 기록 을 삭제 하고 마지막 프로그램 이 종료 할 때 map 에 delete 가 없 는 것 을 인쇄 할 수 있 습 니 다.물론 우 리 는 Crt 가 new 를 실현 할 때 일반적으로 실제 상 향 조정 하 는 것 이 malloc 라 는 것 을 알 고 있 으 며,malloc 는 HeapAlloc 를 조절 할 수도 있 고,HeapAlloc 는 RtlAllocateHeap 을 호출 할 수도 있 기 때문에 이론 적 으로 우 리 는 이 함수 들 의 임 의적 인 차단 과 기록 을 할 수 있다.하지만 크로스 플랫폼 메모리 유출 검 사 를 실현 하려 면 operator new 를 다시 불 러 오 세 요.

좋은 웹페이지 즐겨찾기