C ++ 코드 / 프로젝트에서 메모리 누수를 찾는 방법은 무엇입니까?


180

저는 Windows 플랫폼의 C ++ 프로그래머입니다. Visual Studio 2008을 사용하고 있습니다.

나는 보통 메모리 누수로 코드를 작성합니다.

일반적으로 코드를 검사하여 메모리 누수가 발견되지만 번거롭고 항상 좋은 접근 방식은 아닙니다.

유료 메모리 누수 감지 도구를 사용할 수 없기 때문에 메모리 누수를 피하는 가장 좋은 방법을 제안하기를 원했습니다.

  1. 프로그래머가 메모리 누수를 찾는 방법을 알고 싶습니다.
  2. 프로그램에 메모리 누수가 없는지 확인하기 위해 따라야하는 표준 또는 절차가 있습니까?

29
"보통 코드가 메모리 누수로 끝납니다." 자동 변수, 컨테이너 및 스마트 포인터를 사용하고 스마트 포인터 사용에 대한 모범 사례를 따르는 경우 메모리 누수가 거의 발생하지 않습니다. 기억 거의 모든 경우에, 당신은 자동 리소스 관리를 사용해야합니다 .
James McNellis


1
@Hostile Fork : " 일반적 으로 메모리 누수로 코드가 끝나는 것을 피할 수있는 방법 "은 이러한 답변에 포함되지 않습니다.
Doc Brown

2
@ 닥 브라운 (Doc Brown) : 그것도보고
싶지는 않았지만

1
DIY 누출 감지기 : 의심스러운 코드를 무한 루프에 넣은 다음 작업 관리자를 열 수 있습니다. 일반적으로 약간의 누출로 인해 몇 초 또는 몇 분 안에 메모리가 채워집니다 (코드 복잡성과 CPU에 따라 다름). 이것이 발생하지 않으면 해당 코드 조각이 누출되지 않았을 것입니다.
Hello World

답변:


270

명령

필요한 것

  • C ++ 능력
  • C ++ 컴파일러
  • 디버거 및 기타 조사 소프트웨어 도구

1

운영자 기본 사항을 이해하십시오. C ++ 연산자는 new힙 메모리를 할당합니다. delete조작자 해방 힙 메모리. 모든 newdelete대해 할당 한 동일한 메모리를 확보 할 수 있도록 다음을 사용해야합니다 .

char* str = new char [30]; // Allocate 30 bytes to house a string.

delete [] str; // Clear those 30 bytes and make str point nowhere.

2

삭제 한 경우에만 메모리를 재 할당하십시오. 아래 코드 str에서 두 번째 할당으로 새 주소를 얻습니다. 첫 번째 주소는 복구 할 수 없을 정도로 손실되었으며, 지정한 30 바이트도 손실되었습니다. 이제는 해제가 불가능하며 메모리 누수가 있습니다.

char* str = new char [30]; // Give str a memory address.

// delete [] str; // Remove the first comment marking in this line to correct.

str = new char [60]; /* Give str another memory address with
                                                    the first one gone forever.*/

delete [] str; // This deletes the 60 bytes, not just the first 30.

그 포인터 할당을보십시오. 모든 동적 변수 (힙에 할당 된 메모리)는 포인터와 연관되어야합니다. 동적 변수가 포인터와 연결 해제되면 지울 수 없게됩니다. 다시 말하지만, 메모리 누수가 발생합니다.

char* str1 = new char [30];

char* str2 = new char [40];

strcpy(str1, "Memory leak");

str2 = str1; // Bad! Now the 40 bytes are impossible to free.

delete [] str2; // This deletes the 30 bytes.

delete [] str1; // Possible access violation. What a disaster!

4

로컬 포인터에주의하십시오. 함수에서 선언 한 포인터는 스택에 할당되지만 해당 변수가 가리키는 동적 변수는 힙에 할당됩니다. 삭제하지 않으면 프로그램이 기능을 종료 한 후에도 유지됩니다.

void Leak(int x){

char* p = new char [x];

// delete [] p; // Remove the first comment marking to correct.

}

5

"삭제"후 대괄호에주의하십시오. 사용하여 delete하나의 객체를 무료로 자체. delete []대괄호와 함께 사용 하여 힙 배열을 해제하십시오. 다음과 같이하지 마십시오 :

char* one = new char;

delete [] one; // Wrong

char* many = new char [30];

delete many; // Wrong!

6

누출이 아직 허용 된 경우-일반적으로 deleaker를 사용하여 찾고 있습니다 ( http://deleaker.com ).


3
질문 의견에 대해 죄송하지만 포인터가없는 함수 매개 변수는 어떻습니까? someFunction("some parameter")제가 삭제해야합니까 "some parameter"에서 someFunction함수 호출 후, 또는이 자동으로 삭제됩니다?
19greg96

1
Deleaker와의 링크에 감사드립니다. 이것은 Visual Studio에 깔끔하게 통합 된 매우 편리한 도구입니다. 나는 그것을 사용하여 많은 시간을 절약 할 수 있습니다. 내가 메모리를 할당 한 라인을 가리키고 메모리를 해제하지 않았습니다. 큰. 그리고 내가 찾은 다른 메모리 누수 찾기와 비교하여 저렴합니다.
this.myself

@ john smith plz explan 사례 3과 유사한 사례를 처리하는 올바른 방법은 무엇입니까? str2 = str1; // 나쁘다! 이제 40 바이트를 비울 수 없습니다. str 1을 삭제하는 방법 ??
Nihar

1
char *, int, float, ...와 같은 값 유형을 사용하고 Vector, CString과 같은 구조체를 사용하고 'new'연산자를 전혀 사용하지 않으면 메모리 누수가 발생하지 않습니다. 맞습니까?
123iamking

나는 14 년 가까이에 C ++을 만지지 않았다고 말하기 위해 여기에 있습니다. m은 C #으로 지루합니다. 이 책은 Scott Mitchell의 Effective C ++입니다. 하나님은 그 책을 사랑하셨습니다. 고마워 스캇!
JonH

33

코드에서 일부 기술을 사용하여 메모리 누수를 감지 할 수 있습니다. 감지하는 가장 일반적이고 가장 쉬운 방법은 매크로 말, DEBUG_NEW를 정의하고 같은 미리 정의 된 매크로와 함께 사용된다 __FILE____LINE__코드에서 메모리 누수를 찾습니다. 이러한 사전 정의 된 매크로는 파일 및 행 수의 메모리 누수를 알려줍니다.

DEBUG_NEW는 MACRO 일 뿐이며 일반적으로 다음과 같이 정의됩니다.

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

따라서 어디에서나 사용하면 new프로그램에서 메모리 누수를 찾는 데 사용할 수있는 파일과 줄 번호를 추적 할 수 있습니다.

그리고 __FILE__, __LINE__하는 매크로 미리 정의 당신이 그들을 사용하는 경우 각각 파일 이름과 라인 번호로 평가!

다른 흥미로운 매크로와 함께 DEBUG_NEW를 사용하는 기술을 매우 아름답게 설명하는 다음 기사를 읽으십시오.

플랫폼 간 메모리 누수 탐지기


에서 Wikpedia ,

Debug_new는 C ++에서 메모리 할당 및 할당 취소 호출을 가로 채기 위해 연산자 new 및 operator delete를 오버로드 및 / 또는 재정 의하여 메모리 사용을 위해 프로그램을 디버깅하는 기술을 나타냅니다. DEBUG_NEW라는 매크로를 정의하는 경우가 종종 있으며 new 는 파일 / 라인 정보를 할당 할 때 new (_ FILE _, _ LINE _) 와 같은 형식으로 만듭니다 .Microsoft Visual C ++는이 기술을 Microsoft Foundation 클래스에서 사용합니다. 매크로 재정의를 사용하지 않고 일부 플랫폼에서 파일 / 라인 정보를 계속 표시 할 수 있도록이 방법을 확장 할 수있는 몇 가지 방법이 있습니다. 이 방법에는 많은 고유 한 제한이 있습니다. C ++에만 적용되며 malloc과 같은 C 함수로 메모리 누수를 포착 할 수 없습니다. 그러나 일부 완전한 메모리 디버거 솔루션과 비교할 때 사용이 매우 간단하고 빠를 수도 있습니다.


4
이것은 #define오버로드로 엉망 이 operator new되고 컴파일러 오류가 발생합니다. 이를 극복하더라도 과부하 된 기능은 여전히 ​​해결되지 않습니다. 이 기술은 훌륭하지만 때때로 많은 코드 변경이 필요합니다.
iammilind

1
@iammilind : 물론이 기술은 모든 문제를 완전히 해결하는 것은 아니며 모든 상황에 적용 할 수있는 것은 아닙니다.
Nawaz

@Chris_vr : auto_ptr같은 표준 컨테이너로하지 않습니다 일 std::vector, std::list: 등이 참조 stackoverflow.com/questions/111478/...
나와 즈

좋아. 파일 과 줄에 대해 설명합니다. 사용중인 버전이 무엇이며 무엇입니까 operator new?

14

처음에 메모리 누수가 발생할 위험을 최소화하는 데 도움이되는 잘 알려진 프로그래밍 기술이 있습니다.

  • 고유 한 동적 메모리 할당을 수행해야하는 경우 항상 쌍으로 작성 new하고 delete할당 / 할당 해제 코드를 쌍으로 호출해야합니다.
  • 가능하면 동적 메모리 할당을 피하십시오. 예를 들어, vector<T> t가능한 경우 대신 사용하십시오T* t = new T[size]
  • 부스트 스마트 포인터와 같은 "스마트 포인터"사용 ( http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm )
  • 내가 개인적으로 좋아하는 것 : 포인터의 소유권 개념을 이해했는지 확인하고 포인터를 사용하는 모든 곳에서 어떤 코드 엔티티가 소유자인지 확인하십시오.
  • C ++ 컴파일러가 어떤 생성자 / 할당 연산자를 자동으로 생성하는지, 그리고 포인터를 소유 한 클래스가있는 경우의 의미 또는 소유하지 않은 객체에 대한 포인터가 포함 된 클래스가있는 경우의 의미에 대해 알아 봅니다 .

객체의 auto_pointer를 사용하면 그 안에있는 다른 모든 클래스 객체 포인터가 삭제됩니다.
Chris_vr

@Chris_vr : auto_pointer에 대한 특정 질문이 있으면 예제를 포함하여 새로운 질문을하는 것이 좋습니다.
Doc Brown

많은 게시물에 따르면 vector <>는 메모리가 지워지면 해제되는 것을 보장하지 않습니다. 나는 개인적으로 스왑 물건 등을 테스트했으며 특히 동적으로 사용될 때 vector <>가 누출된다는 결론에 도달했습니다. 'new'및 정리를 사용하여 vector <>가 스스로 동적 할당에 대해 조언 할 수있는 방법을 이해하지 못합니다. 내 임베디드 프로그램에서 모든 누출로 인해 동적 항목에 vector <>를 사용하지 마십시오. 거기에 나는 new 또는 std :: list
bart s

문자 수 때문에 두 번째 명령을 입력합니다. 벡터 <> 동적으로 사용하여 메모리가 부족하면 불행하게도 그러나 내장 된 프로그램이 100 % 확실하다 ... 벡터에 shrink_to_fit이없는 내 포함 된 C ++ 내가 늙은 C를 ++ (? 98)에 완전히 충돌
바트의


8
  1. Windows 용 디버깅 도구를 다운로드 하십시오 .
  2. gflags유틸리티를 사용하여 사용자 모드 스택 추적을 켜십시오.
  3. UMDH프로그램 메모리의 여러 스냅 샷을 만드는 데 사용 합니다. 메모리가 할당되기 전에 스냅 샷을 작성하고 프로그램에서 메모리가 누수되었다고 생각되는 지점에서 두 번째 스냅 샷을 작성하십시오. 프로그램에 일시 중지 또는 프롬프트를 추가 UMDH하여 스냅 샷 을 실행 하고 만들 수있는 기회를 제공 할 수 있습니다 .
  4. UMDH이번에는 두 스냅 샷을 서로 다른 모드로 다시 실행 하십시오. 그런 다음 메모리 누수가 의심되는 호출 스택이 포함 된 보고서를 생성합니다.
  5. gflags완료되면 이전 설정을 복원하십시오 .

UMDH전체 프로세스에서 메모리 할당을 감시하고 있기 때문에 CRT 디버그 힙보다 더 많은 정보를 제공합니다. 타사 구성 요소가 누수되는지 여부를 알려줄 수도 있습니다.


1
나는 Deleaker 대신 표준 프로파일의 Valgrind의 선호
z0r1fan

8

"Valgrind"를 실행하면 다음을 수행 할 수 있습니다.

1) 메모리 누수 식별 - 메모리 누수 수를 표시하고 누수 된 메모리가 할당 된 코드의 행을 가리 킵니다.

2) 메모리를 비 우려는 잘못된 시도 (예 : 부적절한 호출 delete) 를 지적하십시오.

"Valgrind"사용 지침

1) 여기에 valgrind를 얻으 십시오 .

2) -g플래그로 코드를 컴파일하십시오.

3) 쉘에서 다음을 실행하십시오.

valgrind --leak-check=yes myprog arg1 arg2

여기서 "MYPROG는"컴파일 된 프로그램이며 arg1, arg2프로그램의 인수입니다.

4) 결과는 무료 삭제에 대한 후속 호출이 없었던 malloc/ 호출 목록입니다 new.

예를 들면 다음과 같습니다.

==4230==    at 0x1B977DD0: malloc (vg_replace_malloc.c:136)

==4230==    by 0x804990F: main (example.c:6)

malloc(해제되지 않은) 어느 라인에서 호출 되었는지 알려줍니다 .

다른 사람들이 지적했듯이 모든 new/ malloc호출 마다 후속 delete/ free호출 이 있는지 확인하십시오 .


6

gcc를 사용하면 gprof를 사용할 수 있습니다.

프로그래머가 메모리 누수를 찾는 방법을 알고 싶었습니다.

일부는 도구를 사용하고 일부는 피어 코드 검토를 통해 수행 할 수있는 작업을 수행합니다.

프로그램에서 메모리 누수가 없는지 확인하기 위해 따라야하는 표준 또는 절차가 있습니까?

나를 위해 : 동적으로 할당 된 객체를 만들 때마다 항상 해제 코드를 넣은 다음 코드를 채 웁니다. 코드 사이에 예외가없는 것이 확실하면 괜찮습니다. 그렇지 않으면 try-finally를 사용합니다 (C ++을 자주 사용하지 않습니다).


언젠가 생성자에서 할당 된 것을 삭제할 수 없습니다.
Chris_vr

5
  1. Visual Studio에는 C 런타임 라이브러리라는 메모리 누수 탐지기가 내장되어 있습니다. 기본 함수가 리턴 된 후 프로그램이 종료되면 CRT는 애플리케이션의 디버그 힙을 검사합니다. 여전히 디버그 힙에 할당 된 블록이 있으면 메모리 누수가있는 것입니다.

  2. 이 포럼 에서는 C / C ++에서 메모리 누수를 피하는 몇 가지 방법에 대해 설명합니다.


5

의 발생을 코드에서 검색 new하고 소멸자에서 삭제가 일치하는 생성자 내에서 모두 발생하는지 확인하십시오. 이것이 해당 생성자에서 던질 수있는 유일한 작업인지 확인하십시오. 이 작업을 수행하는 간단한 방법은 모두 포인터 래핑하는 것입니다 std::auto_ptr, 또는 boost::scoped_ptr(당신이 의미를 이동할 필요가 있는지 여부에 따라). 미래의 모든 코드의 경우 소멸자의 리소스를 정리하는 객체가 모든 리소스를 소유하고 있는지 확인하십시오. 이동 의미론이 필요한 경우 r- 값 참조를 지원하는 컴파일러로 업그레이드하고 (VS2010은 믿습니다) 이동 생성자를 만들 수 있습니다. 그렇게하고 싶지 않다면 양심적 인 스왑 사용과 관련된 다양한 까다로운 기술을 사용하거나 Boost.Move 라이브러리를 사용해 볼 수 있습니다.


생성자에서 할당 된 메모리를 항상 삭제할 수있는 것은 아닙니다.이 상황을 처리하는 방법
Chris_vr

@Chris_vr 무슨 뜻인가요? 모든 포인터 멤버가 scope_ptr이고 각각이 개별적으로 초기화되면 성공적으로 구성된 모든 멤버가 포인터 를 삭제하고 다른 멤버는 아직 할당 된 메모리에 대한 포인터를 보유하지 않습니다. 일을 마치고 집에 돌아 오면 몇 시간 안에 모범을 보일 것입니다.
Mankarse

@Chris_vr : 특정 예가있는 경우 새 질문으로 게시하여 토론 할 수 있습니다.
Doc Brown

5

Valgrind 도구를 사용하여 메모리 누수를 감지 할 수 있습니다.

또한 특정 함수에서 누수를 찾으려면 함수 끝에 exit (0)을 사용한 다음 Valgrind로 실행하십시오.

`$` valgrind ./your_CPP_program 

5

자동 메모리 누수 검사기 조사

이 답변에서는 이해하기 쉬운 간단한 메모리 누수 예제에서 여러 가지 메모리 누수 검사기를 비교합니다.

: 아무것도하기 전에, 인간에게 알려진 모든 도구를 비교하는 아산 위키에서이 거대한 표를 참조 https://github.com/google/sanitizers/wiki/AddressSanitizerComparisonOfMemoryTools/d06210f759fec97066888e5f27c7e722832b0924을

분석 된 예는 다음과 같습니다.

main.c

#include <stdlib.h>

void * my_malloc(size_t n) {
    return malloc(n);
}

void leaky(size_t n, int do_leak) {
    void *p = my_malloc(n);
    if (!do_leak) {
        free(p);
    }
}

int main(void) {
    leaky(0x10, 0);
    leaky(0x10, 1);
    leaky(0x100, 0);
    leaky(0x100, 1);
    leaky(0x1000, 0);
    leaky(0x1000, 1);
}

GitHub의 상류 .

우리는 서로 다른 도구가 유출 된 통화를 얼마나 명확하게 지적하는지 알아볼 것입니다.

Google gperftools의 tcmalloc

https://github.com/gperftools/gperftools

Ubuntu 19.04에서의 사용법 :

sudo apt-get install google-perftools
gcc -ggdb3 -o main.out main.c -ltcmalloc
PPROF_PATH=/usr/bin/google-pprof \
  HEAPCHECK=normal \
  HEAPPROFILE=ble \
  ./main.out \
;
google-pprof main.out ble.0001.heap --text

프로그램 실행 결과에는 메모리 누수 분석이 포함됩니다.

WARNING: Perftools heap leak checker is active -- Performance may suffer
Starting tracking the heap
Dumping heap profile to ble.0001.heap (Exiting, 4 kB in use)
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 272 bytes in 2 objects
The 2 largest leaks:
Using local file ./main.out.
Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start


If the preceding stack traces are not enough to find the leaks, try running THIS shell command:

pprof ./main.out "/tmp/main.out.24744._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv

If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more re
Exiting with error code (instead of crashing) because of whole-program memory leaks

그리고 출력 google-pprof에는 힙 사용량 분석이 포함됩니다.

Using local file main.out.
Using local file ble.0001.heap.
Total: 0.0 MB
     0.0 100.0% 100.0%      0.0 100.0% my_malloc
     0.0   0.0% 100.0%      0.0 100.0% __libc_start_main
     0.0   0.0% 100.0%      0.0 100.0% _start
     0.0   0.0% 100.0%      0.0 100.0% leaky
     0.0   0.0% 100.0%      0.0 100.0% main

결과는 세 가지 누출 중 두 가지를 나타냅니다.

Leak of 256 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581d3 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start
Leak of 16 bytes in 1 objects allocated from:
        @ 555bf6e5815d my_malloc
        @ 555bf6e5817a leaky
        @ 555bf6e581b5 main
        @ 7f71e88c9b6b __libc_start_main
        @ 555bf6e5808a _start

왜 세 번째가 나타나지 않았는지 모르겠습니다

어쨌든 일반적으로 누수가 발생하면 많은 시간이 걸리고 실제 프로젝트에서 사용했을 때 누수 기능을 매우 쉽게 지적했습니다.

출력 자체에서 언급했듯이 이로 인해 상당한 실행 속도 저하가 발생합니다.

추가 문서 :

참조 : TCMalloc 사용 방법?

우분투 19.04, google-perftools 2.5-2에서 테스트되었습니다.

Google의 Sanitizer (ASan) 주소

https://github.com/google/sanitizers

이전에 언급 : C ++ 코드 / 프로젝트에서 메모리 누수를 찾는 방법은 무엇입니까? TODO 대 tcmalloc.

이것은 이미 GCC에 통합되어 있으므로 다음을 수행 할 수 있습니다.

gcc -fsanitize=address -ggdb3 -o main.out main.c
./main.out 

실행 결과 :

=================================================================
==27223==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 4096 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f210 in main /home/ciro/test/main.c:20
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 256 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1f2 in main /home/ciro/test/main.c:18
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

Direct leak of 16 byte(s) in 1 object(s) allocated from:
    #0 0x7fabbefc5448 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x10c448)
    #1 0x55bf86c5f17c in my_malloc /home/ciro/test/main.c:4
    #2 0x55bf86c5f199 in leaky /home/ciro/test/main.c:8
    #3 0x55bf86c5f1d4 in main /home/ciro/test/main.c:16
    #4 0x7fabbecf4b6a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x26b6a)

SUMMARY: AddressSanitizer: 4368 byte(s) leaked in 3 allocation(s).

모든 누출을 명확하게 식별합니다. 좋은!

ASan은 범위를 벗어난 쓰기와 같은 다른 멋진 검사도 수행 할 수 있습니다. 스택 스매싱 감지

우분투 19.04, GCC 8.3.0에서 테스트되었습니다.

발 그린 드

http://www.valgrind.org/

https://stackoverflow.com/a/37661630/895245 에서 이전에 언급

용법:

sudo apt-get install valgrind
gcc -ggdb3 -o main.out main.c
valgrind --leak-check=yes ./main.out

산출:

==32178== Memcheck, a memory error detector
==32178== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==32178== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==32178== Command: ./main.out
==32178== 
==32178== 
==32178== HEAP SUMMARY:
==32178==     in use at exit: 4,368 bytes in 3 blocks
==32178==   total heap usage: 6 allocs, 3 frees, 8,736 bytes allocated
==32178== 
==32178== 16 bytes in 1 blocks are definitely lost in loss record 1 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091B4: main (main.c:16)
==32178== 
==32178== 256 bytes in 1 blocks are definitely lost in loss record 2 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091D2: main (main.c:18)
==32178== 
==32178== 4,096 bytes in 1 blocks are definitely lost in loss record 3 of 3
==32178==    at 0x483874F: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==32178==    by 0x10915C: my_malloc (main.c:4)
==32178==    by 0x109179: leaky (main.c:8)
==32178==    by 0x1091F0: main (main.c:20)
==32178== 
==32178== LEAK SUMMARY:
==32178==    definitely lost: 4,368 bytes in 3 blocks
==32178==    indirectly lost: 0 bytes in 0 blocks
==32178==      possibly lost: 0 bytes in 0 blocks
==32178==    still reachable: 0 bytes in 0 blocks
==32178==         suppressed: 0 bytes in 0 blocks
==32178== 
==32178== For counts of detected and suppressed errors, rerun with: -v
==32178== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

다시 한번, 모든 누출이 감지되었습니다.

참고 : valgrind를 사용하여 메모리 누수를 찾으려면 어떻게합니까?

우분투 19.04, valgrind 3.14.0에서 테스트되었습니다.


4

VLD (Visual Leak Detector) 는 Visual C ++를위한 강력하고 무료 인 오픈 소스 메모리 누수 탐지 시스템입니다.

Visual Studio 디버거에서 프로그램을 실행하면 Visual Leak Detector가 디버깅 세션이 끝날 때 메모리 누수 보고서를 출력합니다. 누출 보고서에는 누출 된 메모리 블록이 할당 된 방법을 보여주는 전체 호출 스택 이 포함됩니다. 호출 스택에서 라인을 두 번 클릭하여 편집기 창에서 해당 파일로 이동하십시오.

크래시 덤프 만있는 경우 Windbg !heap -l명령을 사용하면 누수 된 힙 블록을 감지합니다. gflags 옵션 인“사용자 모드 스택 추적 데이터베이스 생성”을 열면 메모리 할당 호출 스택이 표시됩니다.


4

MTuner 는 MSVC, GCC 및 Clang 컴파일러를 지원하는 무료 멀티 플랫폼 메모리 프로파일 링, 누출 감지 및 분석 도구입니다. 특징은 다음과 같습니다.

  • 타임 라인 기반 메모리 사용 내역 및 라이브 메모리 블록
  • 힙, 메모리 태그, 시간 범위 등을 기반으로 한 강력한 메모리 작업 필터링
  • 전체 소스 코드로 수동 계측을위한 SDK
  • 명령 줄 사용을 통한 지속적인 통합 지원
  • 호출 스택 트리 및 트리 맵 탐색
  • 훨씬 더.

사용자는 GCC 또는 Clang 크로스 컴파일러를 사용하여 모든 소프트웨어 타겟팅 플랫폼을 프로파일 링 할 수 있습니다. MTuner는 Windows, PlayStation 4 및 PlayStation 3 플랫폼을 기본적으로 지원합니다.


이것이 정답입니다. 훌륭한 도구이며 다른 사람이 할 수없는 할당 / 할당 해제 량을 처리 할 수 ​​있습니다.
Serge Rogatch

3

Windows에서는 CRT 디버그 힙을 사용할 수 있습니다 .

프로그램에 메모리 누수가 없는지 확인하기 위해 따라야하는 표준 또는 절차가 있습니까?

예, 수동 메모리 관리를 사용하지 마십시오 (전화 delete또는 delete[]수동으로 잘못 입력 한 경우). RAII 및 스마트 포인터를 사용하고 힙 할당을 절대 최소값으로 제한하십시오 (대부분 자동 변수로 충분합니다).


3

질문의 두 번째 부분에 대답하면

프로그램에 메모리 누수가 없는지 확인하기 위해 따라야하는 표준 또는 절차가 있습니까?

그렇습니다. 그리고 이것은 C와 C ++의 주요 차이점 중 하나입니다.

C ++에서는 사용자 코드를 호출 new하거나 호출해서는 안됩니다 delete. RAII 는 매우 일반적으로 사용되는 기술로 리소스 관리 문제를 거의 해결합니다. 프로그램의 모든 리소스 (리소스는 파일 핸들, 네트워크 소켓, 데이터베이스 연결 및 일반 메모리 할당 및 경우에 따라 API 호출 쌍 (BeginX ( ) / EndX (), LockY (), UnlockY ())는 다음과 같은 클래스로 래핑되어야합니다.

  • 생성자 리소스를 습니다 ( new리소스가 memroy 할당 인 경우 호출 하여)
  • 소멸자 는 리소스를 해제 하고
  • 복사 및 할당이 방지되거나 (복사 생성자 및 할당 연산자를 개인용으로 만들거나) 기본 리소스를 복제하여 올바르게 작동하도록 구현되었습니다.

이 클래스는 포인터를 호출 하고 저장 하지 않고 로컬, 스택 또는 클래스 멤버로 인스턴스화됩니다 new.

종종 이러한 클래스를 직접 정의 할 필요는 없습니다. 표준 라이브러리 컨테이너도 이러한 방식으로 작동하므로 std::vector벡터가 파괴 될 때에 저장된 객체 가 해제됩니다. 그래서 다시 (필요 컨테이너에 포인터를 저장하지 않습니다 당신이 전화 new하고 delete)이 아니라 객체 자체 (당신은 메모리 관리를 제공합니다 무료을 ). 마찬가지로 스마트 포인터 클래스를 사용하여로 할당해야하는 객체를 쉽게 감싸고 new수명을 제어 할 수 있습니다.

즉, 개체가 범위를 벗어나면 개체가 자동으로 삭제되고 리소스가 해제 및 정리됩니다.

코드 전체에서이 작업을 일관되게 수행하면 메모리 누수가 발생하지 않습니다. 누수 될 수 있는 모든 것은 소멸자에 묶여 있으며, 컨트롤이 객체가 선언 된 범위를 벗어날 때 호출되도록 보장됩니다.


스마트 포인터가 클래스를 보유하고 해당 클래스에 다른 여러 클래스의 포인터가 포함 된 경우 스마트가 꺼지면 내부의 모든 포인터가 안전하게 삭제됩니다.
Chris_vr

@ 크리스 : 가정 객체가 스마트 포인터가 가리키는되고 있다는 것은 필요한 정리를 수행하는 소멸자를 가지고 또는 객체가 자신이 필요한 정리를 수행 할 소멸자가 멤버가 포함되어 있습니다. 본질적으로, 모든 객체가 스스로를 돌보는 한 (파손될 때 스스로 정리), 모든 객체가 포인터가 아닌 값으로 저장되는 한, 해제해야하는 모든 것이 해제 됩니다 .
jalf

3

AddressSanitizer (ASan)는 빠른 메모리 오류 탐지기입니다. C / C ++ 프로그램에서 use-after-free 및 {heap, stack, global} 버퍼 오버 플로우 버그를 찾습니다. 다음을 찾습니다.

  • 해제 후 사용 (매달린 포인터 역 참조)
  • 힙 버퍼 오버 플로우
  • 스택 버퍼 오버 플로우
  • 글로벌 버퍼 오버 플로우
  • 반품 후 사용
  • 초기화 순서 버그

이 도구는 매우 빠릅니다. 계측 프로그램의 평균 속도 저하는 ~ 2x입니다.



0

다른 코드에서 제공되는 도구 및 방법 외에도 정적 코드 분석 도구를 사용하여 메모리 누수 (및 기타 문제)를 감지 할 수 있습니다. 강력한 무료 도구는 Cppcheck입니다. 그러나 사용 가능한 다른 도구가 많이 있습니다. Wikipedia 에는 정적 코드 분석 도구 목록이 있습니다.


-1

모든 힙 메모리가 성공적으로 비워 졌는지 확인하십시오. 힙에 메모리를 할당하지 않으면 필요하지 않습니다. 그럴 경우, 메모리를 malloc 한 횟수를 세고 메모리를 확보 한 횟수를 세십시오.


-3

"새로운"또는 "삭제"는 응용 프로그램 코드에서 사용해서는 안됩니다. 대신 관리자 / 작업자 관용구를 사용하는 새 유형을 작성하십시오. 여기서 관리자 클래스는 메모리를 할당 및 해제하고 다른 모든 조작을 작업자 오브젝트로 전달합니다.

불행히도 이것은 C ++에 "operator"의 과부하가 없기 때문에 필요한 것보다 더 많은 작업입니다. 다형성이있는 경우 훨씬 더 많은 작업입니다.

그러나 메모리 누수에 대해 걱정할 필요가 없으므로 찾아 볼 필요가 없기 때문에 노력할 가치가 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.