C++에서 메모리 누수 찾기

Saad Aslam 2024년2월16일
  1. C++의 메모리 누수
  2. C++에서 메모리 누수 처리
  3. C++에서 메모리 누수를 방지하는 방법
  4. Valgrind를 사용하여 C++에서 메모리 누수 찾기
  5. CRT 라이브러리를 사용하여 C++에서 메모리 누수 찾기
C++에서 메모리 누수 찾기

이 기사에서는 메모리 누수, 그 원인, 이를 식별하는 방법 및 C++ 프로그래밍 언어를 사용하여 이를 방지하는 방법에 대해 설명합니다.

C++의 메모리 누수

프로그래머가 이전에 한 목적에 할당한 메모리 부분이 다른 용도로 사용되는 경우 메모리가 “누수"되었다고 합니다. 이와 같은 일이 발생하면 프로그래머는 리소스 할당을 올바르게 해제하지 않습니다.

이 시점에서 프로그램은 그러한 RAM을 사용할 필요가 없습니다. 결과적으로 해당 좌석에 대한 예약을 유지할 이유가 없습니다.

프로그래머가 new 키워드를 사용하여 메모리를 할당했지만 delete() 함수 또는 delete[] 연산자를 사용하여 메모리 할당을 해제하지 못하는 경우 C++에서 메모리 누수가 발생합니다. 이로 인해 메모리가 손실됩니다. 대부분의 경우 잘못된 delete 연산자로 인해 메모리 누수가 발생합니다.

delete[] 연산자는 배열의 데이터를 해제할 수 있습니다.

우리가 자동차의 오일을 갈 때 실링을 교체하거나 나사를 조이는 것을 동시에 소홀히 한다면 우리는 운전할 때 심각한 문제에 봉착할 가능성이 높습니다.

우리 자동차의 엔진은 결국 모든 기름이 차 밖으로 흘러나올 것이기 때문에 결국 멈출 것입니다. C++ 프로그래밍은 정확히 같은 결과를 가져올 것입니다.

프로그래머가 메모리를 동적으로 할당했지만 나중에 해당 메모리를 해제하지 않으면 메모리 누수가 발생하고 메모리 할당은 다음과 같이 수행될 수 있습니다.

int *data;
data = (int *)malloc(8);
char *login = new char(40);

메모리를 동적으로 할당할 때 해당 메모리는 C++이 활용하는 시스템 메모리의 일부인 힙에서 가져옵니다. 스택은 변수와 함수를 가져오는 곳입니다.

이러한 할당을 정리하기 위해 다음 코드를 추가하지 않으면 메모리 누수가 발생합니다. 이러한 누출은 시간이 지남에 따라 축적되며 프로그램 논리에 따라 응용 프로그램이 실패할 수 있습니다.

free(data);
delete login;

다음은 포인터에 대해 8바이트의 힙 공간을 할당하기 위해 함수를 만드는 또 다른 경우입니다. 이것은 64비트 컴퓨터에서 8바이트를 차지합니다.

해당 바이트는 프로그램 실행이 완료된 후 해제되지 않습니다.

#include <iostream>
using namespace std;

void data_leak() { double *pointer = new double(28.54); }
int main() { data_leak(); }

위의 코드 블록에 다음 루프 코드를 추가하면 백만 바이트가 할당되지만 해제되지는 않습니다. 이 코드를 실행하기 전에 열려 있는 파일을 모두 저장해야 합니다.

최첨단 운영 체제에서도 문제가 없지만 for 루프에 추가 명령을 추가하면 문제가 발생할 수 있습니다. 이것이 메모리 누수가 매우 위험한 이유입니다.

for (int j = 0; j < 150000; j++) {
  data_leak();
}

C++에서 메모리 누수 처리

먼저 func_to_handle_memory_leak(),라는 함수를 만들고 메모리 누수를 처리할 정수형 포인터를 선언한 다음 new int() 키워드로 정수 값을 할당합니다.

void func_to_handle_memory_leak() { int* ptr = new int(6); }

이제 delete() 함수를 사용하여 이전 메모리를 지우고 프로그램에서 메모리 누수를 방지합니다. 모든 활동은 함수가 호출되는 즉시 수행되며 할당된 메모리는 함수가 반환되기 전에 해제됩니다.

delete (ptr);

main 함수에서 func_to_handle_memory_leak() 함수를 호출합니다.

int main() {
  func_to_handle_memory_leak();
  return 0;
}

전체 소스 코드:

#include <iostream>
using namespace std;

void func_to_handle_memory_leak() {
  int* ptr = new int(6);
  delete (ptr);
}
int main() {
  func_to_handle_memory_leak();
  return 0;
}

C++에서 메모리 누수를 방지하는 방법

  1. 메모리를 일일이 손으로 관리하기보다 가능하면 스마트 포인터를 활용하는 노력을 해야 합니다.
  2. char\* 대신 std::string을 사용해야 합니다. std::string 클래스는 매우 빠르고 고도로 최적화되어 있습니다. 내부적으로 모든 메모리 관리를 처리합니다.
  3. C++에서 메모리 누수를 방지하는 가장 좋은 방법은 프로그램 수준에서 몇 가지 newdelete 호출을 하는 것입니다. 동적 메모리가 필요한 모든 항목은 범위를 벗어날 때 메모리를 해제하는 RAII 개체 내부에 묻혀 있어야 합니다. RAII는 변수가 현재 범위를 벗어날 때 메모리가 할당 해제되도록 생성자에서 메모리를 할당하고 소멸자에서 해제합니다.
  4. 메모리는 new 키워드를 사용하여 할당해야 하며 메모리는 delete 키워드를 사용하여 할당 해제해야 합니다. 모든 코드는 이 두 명령 사이에 작성됩니다.

Valgrind를 사용하여 C++에서 메모리 누수 찾기

메모리 누수는 시스템 메모리를 소진하고 malloc 호출이 실패할 때까지 눈에 띄는 문제로 나타나지 않기 때문에 가장 교활한 종류의 프로그래밍 오류 중 하나입니다.

실제로 가비지 수집이 없으면 C 또는 C++와 같은 언어를 처리할 때 메모리가 적절하게 해제되었는지 확인하는 데 노력의 약 절반이 소요될 수 있습니다.

현재 지원되는 도구 목록을 보려면 Valgrind를 실행한 다음 코드를 실행할 때 사용할 도구를 선택하십시오.

memcheck 도구로 Valgrind를 실행하면 정확한 메모리 소비를 확인할 수 있습니다. 모든 freemalloc 호출에 대한 요약을 제공합니다.

설명을 위해 memoryleakdemo라는 기본 프로그램을 사용하겠습니다.

#include <stdlib.h>

int main() {
  char *x = new char[100];
  return 0;
}

그러면 해당 자유 호출이 없는 malloc 호출 목록을 포함하여 프로그램에 대한 일부 정보가 표시됩니다.

% valgrind --tool=memcheck --leak-check=yes memoryleakdemo

우리는 main에서 malloc에 대한 호출이 메모리 누수의 원인이라는 것을 알고 있지만 특정 줄 번호를 찾을 수 없습니다. 문제는 디버깅 기호를 제공하는 GCC의 -g 옵션을 사용하여 프로그램을 빌드하지 않았다는 것입니다.

다음 출력은 디버깅 기호를 사용하여 프로그램을 다시 컴파일하면 얻을 수 있는 것입니다.

==2022== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1
==2022==    at 0x1B900DD0: malloc (vg_replace_malloc.c:131)
==2022==    by 0x804840F: main (memoryleakdemo.c:5)

CRT 라이브러리를 사용하여 C++에서 메모리 누수 찾기

메모리 누수는 Visual Studio 디버거 및 C 런타임(CRT) 라이브러리를 사용하여 찾고 식별할 수 있습니다.

메모리 누수 감지 활성화

디버그 힙 기능을 활성화하려면 애플리케이션에 다음 문을 포함해야 합니다.

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

이러한 명령을 사용하여 디버그 힙 기능을 활성화한 후 프로그램이 종료될 때 메모리 누수 보고서가 표시되도록 애플리케이션 종료 지점 앞에 _CrtDumpMemoryLeaks에 대한 호출을 삽입할 수 있습니다.

_CrtDumpMemoryLeaks();

메모리 누수 보고서는 _CrtDumpMemoryLeaks가 실행될 때 Output 창의 Debug 탭으로 전송됩니다. 이것이 기본 동작입니다.

_CrtSetReportMode 기능을 사용하여 보고서를 다른 위치로 보낼 수 있습니다.

CRT 라이브러리 메모리 누수의 출력:

_CrtDumpMemoryLeaks는 애플리케이션이 _CRTDBG MAP ALLOC를 선언하지 않는 경우 아래와 유사한 메모리 누수 보고서를 생성합니다.

Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
 Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

애플리케이션이 _CRTDBG MAP ALLOC를 지정하는 경우 메모리 누수 보고서는 다음과 같이 표시됩니다.

Detected memory leaks!
Dumping objects ->
c:\users\username\documents\projects\leaktest\leaktest.cpp(20) : {18}
 normal block at 0x00780E80, 64 bytes long.
 Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
작가: Saad Aslam
Saad Aslam avatar Saad Aslam avatar

I'm a Flutter application developer with 1 year of professional experience in the field. I've created applications for both, android and iOS using AWS and Firebase, as the backend. I've written articles relating to the theoretical and problem-solving aspects of C, C++, and C#. I'm currently enrolled in an undergraduate program for Information Technology.

LinkedIn

관련 문장 - C++ Memory