(관리되지 않는) 코드에서 메모리 누수를 어떻게 감지 / 방지합니까? [닫은]


125

관리되지 않는 C / C ++ 코드에서 메모리 누수를 감지하는 가장 좋은 방법은 무엇입니까? 코딩 지침은 피해야합니까? (그렇다면 간단합니다.)

우리는 과거에 약간의 어리석은 방식을 사용했습니다. 즉, 모든 메모리 할당 호출에 대해 카운터 증분을하고 해제하는 동안 감소합니다. 프로그램이 끝나면 카운터 값은 0이어야합니다.

나는 이것이 좋은 방법이 아니며 몇 가지 캐치가 있음을 알고 있습니다. (예를 들어, 플랫폼 API 호출에 의해 할당 된 메모리를 해제하는 경우 할당 계수는 해제 횟수와 정확히 일치하지 않습니다. 물론 메모리를 할당 한 API 호출을 호출 할 때 카운터를 증가 시켰습니다.)

나는 당신의 경험, 제안 및 이것을 단순화시키는 도구에 대한 언급을 기대하고 있습니다.


누출을 피하기 위해 다음 게시물에 조언이 있습니다. http://stackoverflow.com/questions/27492/c-memory-management
tonylo


나는 이것을 시각적 스튜디오와 함께 사용하여 멤 누출을 감지했습니다. codeproject.com/KB/applications/visualleakdetector.aspx
tiboo

1
당신은 또한 ... 비주얼 누설 감지기를 찾거나 (Windows 용) deleaker (리눅스 용) valgrin searh
존 스미스

메모리 누수를 찾으 려면
Vijay

답변:


78

C / C ++ 코드를 * nix로 이식 할 수있는 경우 Valgrind 보다 나은 점은 거의 없습니다 .


1
Valgrind는 이제 OS X에서도 작동하므로 Linux가 유일한 옵션은 아닙니다.
Michael Anderson

1
Linux 및 OS X 용 Valgrind. windose를 사용하면-deleaker-무엇보다도!
John Smith

@JordiBunster : 니스! 그러나 런타임 기반. 큰 코드 기반 (경우에 따라 C로 작성) 을 사용하면 프로그램의 설계 방식을 주로 테스트하게됩니다. 공격자는 메모리 누수 악용을 찾기 위해 코드를 읽는 데 수천 시간이 소요될 수 있습니다. JavaScript에 존재하는 것과 유사한 소스 코드 분석을위한 자동화 된 도구를 기대했을 것입니다.
user2284570

65

Visual Studio를 사용하는 경우 Microsoft는 메모리 누수를 감지하고 디버깅하는 데 유용한 기능을 제공합니다.

이 기사로 시작하겠습니다 : https://msdn.microsoft.com/en-us/library/x98tx3cf(v=vs.140).aspx

다음은 해당 기사에 대한 간략한 요약입니다. 먼저 다음 헤더를 포함하십시오.

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

그런 다음 프로그램이 종료 될 때 이것을 호출해야합니다.

_CrtDumpMemoryLeaks();

또는 매번 같은 장소에서 프로그램이 종료되지 않으면 프로그램 시작시이를 호출 할 수 있습니다.

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

이제 프로그램이 종료되면 할당되지 않은 모든 할당이 할당 된 파일 및 할당 발생과 함께 출력 창에 인쇄됩니다.

이 전략은 대부분의 프로그램에서 작동합니다. 그러나 어떤 경우에는 어렵거나 불가능 해집니다. 시작시 일부 초기화를 수행하는 타사 라이브러리를 사용하면 메모리 덤프에 다른 개체가 표시되어 누출을 추적하기 어려울 수 있습니다. 또한 클래스에 메모리 할당 루틴 (예 : malloc)과 이름이 같은 멤버가있는 경우 CRT 디버그 매크로가 문제를 발생시킵니다.

위에서 참조한 MSDN 링크에 설명 된 다른 기술도 사용할 수 있습니다.


이 방법에 대한 참고 사항 : malloc과 함께 순수 C를 사용하고 무료 인 경우에만 작동하는 것으로 보입니다. c ++의 new 및 delete를 사용하는 경우 행 번호를 포함하는 자세한 보고서가 작성되지 않습니다.
Zach

2
@Zach : 실제로이 작업을 수행 할 수도 있습니다 (실제로 자신을 컴파일하는 모든 코드에 대해) -social.msdn.microsoft.com/forums/en-US/vcgeneral/thread/
Roman Starkov

릴리스 모드에서도 작동합니까?
JV

1
@ user3152463 아니요. 설명서에 따르면 디버그 빌드에서만 작동합니다. msdn.microsoft.com/en-us/library/e5ewb1h3(v=vs.71).aspx
Dusty Campbell

이 줄은 잘못되었습니다 : #define CRTDBG_MAP_ALLOC 다음과 같아야합니다 : #define _CRTDBG_MAP_ALLOC
Fallso

37

C ++에서 : RAII를 사용하십시오. 스마트 포인터 좋아 std::unique_ptr, std::shared_ptr, std::weak_ptr친구입니다.


1
std : vector는 배열 (버퍼)이 할당 된 동일한 기능으로 할당 해제 될 때를 대체합니다.
KJAWolf

4
적어도 std :: auto_ptr 및 boost :: shared_ptr은 여전히 ​​누수에 취약합니다.
Jasper Bekkers

5
std :: auto_ptr에 대해 잘못 사용하면 매우 쉽다는 것을 인정해야하지만 잘못 사용하는 경우에만 가능합니다.
Leon Timmermans

2
이것이 코딩 표준에 대한 좋은 조언이지만 질문에 대답하지는 않습니다. shared_ptr을 사용하더라도 순환 종속성으로 누수가 발생할 수 있습니다. 그리고 가비지 수집 언어에도 적용되는 무제한 캐싱 전략으로 "누설"을 가질 수 있습니다.
CashCow

@CashCow : 맞습니다. 아직 실제로는 보지 못했지만 아마도 사용하지 않기 때문일 수 있습니다. 아래의 대답을 인용하려면 "절대적으로 필요한 경우에만 포인터를 사용하십시오".
레온 Timmermans

28

C ++ 개발자는 다음과 같은 간단한 지침을 제공합니다.

  1. 꼭 필요한 경우에만 포인터를 사용하십시오
  2. 포인터가 필요한 경우 SmartPointer 가 가능한지 다시 확인하십시오.
  3. GRASP Creator 패턴을 사용하십시오 .

개인적으로 메모리 누수 감지에 대해서는 항상 Visual Leak Detector를 사용 했으며 매우 유용하다고 생각했습니다.


2
비주얼 누출 Detectore는 새 사이트로 이동 vld.codeplex.com
KindDragon

VLD는 정말 훌륭한 누출 감지기입니다. VC ++를 사용하는 모든 사람에게 완전히 권장합니다
Javid

1
포인트 # 1의 경우 +1 이것은 절대적으로 근본적인 것입니다. 불행히도, 가장 큰 "C ++"라이브러리 중 일부는 종종 알 수없는 이유없이 Pointers Everywhere에 찬성하여 스택 할당 및 / 또는 RAII를 피하는 경향이 있습니다. 따라서 실제 C ++이 아닌 'C with Classes'가됩니다.
underscore_d

16

지금까지 너무 오랫동안 DevStudio를 사용해 왔으며 디버그 런타임 라이브러리에서 사용할 수있는 메모리 분석 도구에 대해 얼마나 많은 프로그래머가 알지 못하는지 항상 놀랍습니다. 시작하는 몇 가지 링크는 다음과 같습니다.

힙 할당 요청 추적 -특히 고유 할당 요청 번호 섹션

_CrtSetDbgFlag

_CrtSetBreakAlloc

물론 DevStudio를 사용하지 않는다면 특별히 도움이되지 않습니다.



7

Visual Leak Detector는 VC9 런타임 (예 : MSVCR90D.DLL)에서 호출을 지원하지 않지만 매우 유용한 도구입니다.


1
이 도구는 정말 완벽합니다! _CrtDumpMemoryLeaks ()를 사용하면 문제가 발생하지 않습니다. MSDN에 설명 된대로 친구. 하나만 포함하면 모든 것이 노출됩니다! 오래된 C 라이브러리에서도 작동합니다!
m_pGladiator

새 버전 (VS2013 용)은 다음과 같습니다. vld.codeplex.com
Dženan

7

디버그 모드의 Microsoft VC ++는 누수 위치를 보여주지는 않지만 메모리 누수를 보여줍니다.

C ++를 사용하는 경우 항상 명시 적으로 new를 사용하지 않아도됩니다 vector. string,, auto_ptr(pre C ++ 11; unique_ptrC ++ 11에서 대체 됨 ), unique_ptr(C ++ 11) 및 shared_ptr(C ++ 11)은 무기고에 있습니다.

new를 피할 수없는 경우, 생성자에서 숨기고 소멸자에서 delete를 숨기십시오. 타사 API에서도 마찬가지입니다.


1
그리고 3 또는 5의 규칙을 잊지 마세요
Humam Helfawi

4

거기에는 다양한 대체 "malloc"라이브러리가 있으며 끝에 함수를 호출 할 수 있으며 사용되지 않은 모든 메모리에 대해 알려줄 것이며 많은 경우 처음에 누가 malloc (또는 새로 추가)했는지 알려줍니다. .


4

MS VC ++를 사용하는 경우 코드 프로젝트에서 leak freefinder 를 사용하는 것이 좋습니다. 에서 Jochen Kalmbach의 를 .

수업을 프로젝트에 추가하고 전화하십시오.

InitAllocCheck(ACOutput_XML)
DeInitAllocCheck()

누출 여부를 확인하려는 코드 전후.

코드를 빌드하고 실행하면 Jochen은 결과 .xmlleaks 파일을로드하고 각 누출이 발생한 호출 스택을 탐색하여 문제가되는 코드 행을 찾아 낼 수있는 깔끔한 GUI 도구를 제공합니다.

Rational의 (현재 IBM 소유) PurifyPlus는 유사한 방식으로 누출을 설명하지만 누출 감지기는 실제로 수천 달러가 들지 않는 보너스로 사용하기가 더 쉽다는 것을 알게되었습니다!


1
누출 감지기를 확인했는데 괜찮아 보이지만 인라인 어셈블리가 포함되어 있기 때문에 x64에서는 그대로 작동하지 않습니다.
Zach


3

Visual Studio를 사용하는 경우 Bounds Checker를 살펴볼 가치가 있습니다 . 무료는 아니지만 코드에서 누수를 찾는 데 매우 도움이되었습니다. 메모리 누수뿐만 아니라 GDI 리소스 누수, WinAPI 사용 오류 및 기타 작업도 수행합니다. 누출 된 메모리가 초기화 된 위치를 표시하여 누출을 훨씬 쉽게 추적 할 수 있습니다.


2

나는이 질문에 대한 쉬운 대답이 없다고 생각합니다. 이 솔루션에 실제로 접근하는 방법은 요구 사항에 따라 다릅니다. 크로스 플랫폼 솔루션이 필요하십니까? 신규 / 삭제 또는 malloc / free (또는 둘 다)를 사용하고 있습니까? 실제로 "누설"만 찾고 있습니까, 아니면 버퍼 오버런 (또는 언더런) 감지와 같은 더 나은 보호를 원하십니까?

Windows 측에서 작업하는 경우, MS 디버그 런타임 라이브러리에는 몇 가지 기본 디버그 감지 기능이 있으며, 이미 지적했듯이 누출 감지를 돕기 위해 소스에 포함 할 수있는 여러 랩퍼가 있습니다. 새 / 삭제 및 malloc / free와 함께 작동 할 수있는 패키지를 찾는 것은 분명히 더 많은 유연성을 제공합니다.

나는 유닉스 측이 도움을 줄만큼 충분히 알지 못하지만 다른 사람들도 도움을 줄 수 있습니다.

그러나 누출을 감지하는 것 외에도 버퍼 오버런 (또는 언더런)을 통해 메모리 손상을 감지하는 개념이 있습니다. 이 유형의 디버그 기능은 일반 누출 감지보다 더 어렵다고 생각합니다. C ++ 객체로 작업하는 경우 이러한 유형의 시스템은 여러 가지 방법으로 삭제할 수 있기 때문에 삭제되는 실제 기본 포인터를 결정하기가 까다로워지기 때문에 더 복잡합니다. 나는 오버런을 적절히 보호하는 좋은 "무료"시스템이 없다는 것을 알고있다. 우리는 시스템 (크로스 플랫폼)을 작성했으며 꽤 어려운 것으로 나타났습니다.


2

나는 과거에 때때로 사용했던 것을 제공하고 싶다 : 소스 레벨이며 상당히 자동적 인 기초 누설 검사기. 나는 세 가지 이유로 이것을 포기하고 있습니다 :

  1. 유용 할 수 있습니다.

  2. 약간 krufty이지만, 나는 그것을 당황하게하지 않습니다.

  3. 비록 일부 win32 훅에 묶여 있지만, 완화하기 쉬워야합니다.

사용시주의해야 할 사항이 있습니다. 기대어야 할 일은하지 마십시오. new . 기본 코드 leakcheck.cpp 상단에서 놓칠 수있는 경우에 대한 경고에주의하십시오. 이미지 덤프를 수행하는 코드에서 문제를 해결하면 큰 파일이 생성 될 수 있습니다.

이 디자인은 헤더를 포함하는 모든 것을 다시 컴파일하지 않고도 체커를 켜거나 끌 수 있도록 설계되었습니다. 확인을 추적하고 한 번 다시 빌드하려는 곳에 leakcheck.h를 포함하십시오. 그런 다음 LEAKCHECK # define'd를 사용하거나 사용하지 않고 leakcheck.cpp를 컴파일 한 다음 다시 연결하여 켜거나 끕니다. unleakcheck.h를 포함하면 파일에서 로컬로 끕니다. 두 개의 매크로가 제공됩니다. CLEARALLOCINFO ()는 leakcheck.h를 포함하지 않은 코드를 할당 할 때 동일한 파일과 행을 부적절하게보고하지 않습니다. ALLOCFENCE ()는 할당을 수행하지 않고 생성 된 보고서에서 한 줄만 삭제합니다.

다시 한 번, 나는 이것을 사용하지 않았으며 조금만 사용해야 할 수도 있습니다. 나는 아이디어를 설명하기 위해 그것을 떨어 뜨리고있다. 충분한 관심이있는 것으로 판명되면 프로세스에서 코드를 업데이트하고 예제를 작성하고 다음 URL의 내용을 적절한 구문 색상 목록을 포함하는 더 좋은 것으로 바꿉니다.

여기에서 찾을 수 있습니다 : http://www.cse.ucsd.edu/~tkammeye/leakcheck.html



2

누출에 대한 최선의 방어책은 malloc의 사용을 최소화하는 프로그램 구조입니다. 이는 프로그래밍 측면에서 우수 할뿐만 아니라 성능 및 유지 관리 성을 향상시킵니다. malloc 대신 다른 것을 사용하는 것에 대해 이야기하는 것이 아니라 객체를 재사용하고 가비지 컬렉터가있는 언어에서 자주 사용되는 것처럼 willy-nilly를 할당하는 대신 전달되는 모든 객체에 대해 매우 명확한 탭을 유지한다는 측면에서 자바처럼.

예를 들어, 내가 작업하는 프로그램에는 이미지 데이터를 나타내는 많은 프레임 객체가 있습니다. 각 프레임 객체에는 프레임의 소멸자가 해제하는 하위 데이터가 있습니다. 프로그램은 할당 된 모든 프레임의 목록을 유지하고 새로운 프레임이 필요할 때 사용하지 않는 프레임 객체의 목록을 확인하여 새 프레임을 할당하는 대신 기존 프레임을 재사용 할 수 있는지 확인합니다. 종료되면 목록을 반복하여 모든 것을 해제합니다.


2

메모리 검사기를 사용하는 것이 좋습니다소프트웨어 확인에서 를 . 이 도구는 메모리 누수를 추적하고 현재 작업중인 응용 프로그램의 메모리 관리를 개선하는 데 도움이되는 귀중한 도움이되었습니다.

매우 완전하고 빠른 도구입니다.


메모리 검사기는 기본 코드를 호출하는 C #의 파일 이름과 줄 번호도 제공합니다. x64 버전은 베타 버전입니다
스티븐 Kellett

2

호출을 기록한 다음 호출을 실제 함수로 전달하는 고유 한 syscall 함수를 보간하여 할당량을 계산하고 해제합니까?

이것은 아직 작성하지 않은 코드에서 발생하는 통화를 추적 할 수있는 유일한 방법입니다.

ld.so의 매뉴얼 페이지를 살펴보십시오. 또는 일부 시스템에서는 ld.so.1입니다.

또한 Google LD_PRELOAD를 수행하면 www.itworld.com에서이 기술을 설명하는 흥미로운 기사를 찾을 수 있습니다.


1

적어도 MS VC ++의 경우 C 런타임 라이브러리에는 과거에 도움이 된 몇 가지 기능이 있습니다. _Crt*기능에 대한 MSDN 도움말을 확인하십시오 .


1

Paul Nettle의 mmgr 은 오랫동안 선호하는 도구입니다. 소스 파일에 mmgr.h를 포함시키고 TEST_MEMORY를 정의하면 앱 실행 중에 발생한 메모리 문제로 가득 찬 텍스트 파일이 제공됩니다.


1

일반 코딩 지침 :

  • 리소스는 할당 된 동일한 "계층"(함수 / 클래스 / 라이브러리)에 할당 해제되어야합니다.
  • 이것이 가능하지 않으면 자동 할당 해제 (부스트 공유 포인터 ...)를 사용하십시오.

1

메모리 디버깅 도구는 금의 가치가 있지만 몇 년 동안 두 가지 간단한 아이디어를 사용하여 대부분의 메모리 / 리소스 누수가 처음부터 코딩되는 것을 방지 할 수 있음을 발견했습니다.

  1. 할당하려는 리소스에 대한 획득 코드를 작성한 후 즉시 릴리스 코드를 작성하십시오. 이 방법을 사용하면 "잊어 버린"것이 어려워지고 어떤 의미에서 자원의 수명주기를 제쳐두 기보다는 선결제로 사용하는 것을 진지하게 생각해야합니다.

  2. 가능한 한 희소하게 반환을 사용하십시오. 할당 된 것은 가능하면 한 곳에서만 해제해야합니다. 자원 획득과 릴리스 사이의 조건부 경로는 가능한 한 간단하고 명확하게 설계되어야합니다.


1

이 목록의 맨 위에 (내가 읽을 때) valgrind였습니다. 테스트 시스템에서 누출을 재현 할 수 있으면 Valgrind가 우수합니다. 나는 그것을 큰 성공으로 사용했습니다.

프로덕션 시스템이 현재 누출되고 있으며 테스트에서 재현하는 방법을 모른다면 어떻게해야합니까? 문제의 일부 증거는 해당 프로덕션 시스템의 상태에서 캡처되며 문제의 위치에 대한 통찰력을 제공하여 문제를 재현 할 수 있습니다.

그것이 몬테카를로 샘플링이 등장한 곳입니다. Raymond Chen의 블로그 기사 "가난한 사람이 메모리 누수를 식별하는 방법"을 읽고 내 구현을 확인하십시오 (Linux는 x86 및 x86-64에서만 테스트 된 것으로 가정).

http://github.com/tialaramex/leakdice/tree/master


1

Motorola 휴대폰 운영 체제에서 작업하면서 모든 메모리 할당을 관찰하기 위해 메모리 할당 라이브러리를 탈취했습니다. 메모리 할당과 관련된 많은 문제를 찾는 데 도움이되었습니다. 예방이 치료보다 낫기 때문에 Klockwork 또는 PC-Lint 와 같은 정적 분석 도구를 사용하는 것이 좋습니다


splint는 보푸라기를위한 새로운 대체품입니다.
Mark Kegel

@ user14788 : Gimpel의 PC-Lint 제품은 이전 Unix보다 훨씬 현대적 lint입니다. C ++에 대한 많은 검사가 있지만 apaik splint는 그렇지 않습니다. 답변의 링크를 참조하십시오 (Lint에서 PC-Lint로 이름이 바)).
Dan

0

Valgrind는 리눅스를위한 훌륭한 옵션입니다. MacOS X에서는 메모리 할당 문제를 디버깅하기위한 여러 옵션이있는 MallocDebug 라이브러리를 활성화 할 수 있습니다 (malloc 맨 페이지의 "ENVIRONMENT"섹션에 관련 세부 사항이 있음)을 참조하십시오. 또한 OS X SDK에는 MallocDebug (일반적으로 / Developer / Applications / Performance Tools /에 설치됨)라는 도구가 포함되어있어 사용량 및 누출을 모니터링 할 수 있습니다.



0

멋진 malloc, calloc 및 reallloc 대체는 rmdebug이며 사용하기가 매우 간단합니다. valgrind하는 것이 훨씬 빠르므로 코드를 광범위하게 테스트 할 수 있습니다. 물론 누출이 발견되면 valgrind를 사용하여 누출이 나타나는 곳을 찾아야하며 직접 수행하는 mallocs 만 테스트 할 수 있습니다. lib를 잘못 사용하여 lib가 누출되면 rmdebug가 찾지 못합니다.

http://www.hexco.de/rmdebug/


0

대부분의 메모리 프로파일 러는 복잡한 Windows 응용 프로그램을 결과가 쓸모없는 지점으로 늦 춥니 다. - UMDH : 내 응용 프로그램에서 발견 누출 잘 작동 하나의 도구가 http://msdn.microsoft.com/en-us/library/ff560206%28VS.85%29.aspx은


왜 둔화가 결과를 쓸모 없게 만드는지 알 수 없습니다. 유출 된 메모리는 프로그램 실행 속도에 관계없이 유출됩니다. 이 도구의 핵심은 누수를 찾는 것이므로 문제가 어디입니까? 프로파일 링을 위해 모든 코드 경로를 물리적으로 처리 할 수 ​​없을 정도로 느리게 실행 되었습니까?
underscore_d

-1

Mtrace 는 리눅스에서 기본으로 제공되는 것으로 보입니다. 단계는 다음과 같습니다.

  1. bash에서 환경 변수 MALLOC_TRACE를 설정하십시오.
    MALLOC_TRACE = / tmp / mtrace.dat
    export MALLOC_TRACE;
  2. 기본 소스 파일 맨 위에 #include <mcheck.h> 를 추가 하십시오.
  3. mtrace ()를 추가하십시오 ; main과 muntrace () 의 시작에서 ;맨 아래 (반품 명세서 앞)
  4. 디버그 정보를 위해 -g 스위치를 사용하여 프로그램을 컴파일하십시오.
  5. 프로그램을 실행

  6. mtrace your_prog_exe_name /tmp/mtrace.dat 와 함께 누출 정보 표시
    ( yum install glibc_utils 사용 하여 fedora 시스템에 mtrace perl 스크립트를 먼저 설치해야 함   )

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