카테고리 없음

[TIL] 언리얼 부트캠프 Day9 : C++ 동적 메모리 누수가 일어나는 이유

pal2tte 2024. 12. 27. 20:47

동적 메모리 누수(memory leak)란, 프로그램에서 동적으로 할당된 메모리가 해제되지 않고 사용 가능한 상태로 남아 있어, 더 이상 접근할 수 없는 상황을 말합니다. 이 문제는 주로 new로 메모리를 할당했으나, 대응되는 delete를 호출하지 않아서 발생합니다.


1. 메모리 누수의 발생 과정

동적 메모리는 new 키워드를 사용하여 프로그램 실행 중에 힙(Heap) 메모리에 할당됩니다. 하지만 해당 메모리를 해제하지 않으면, 프로그램이 종료될 때까지 그 메모리가 유지됩니다.

예제:

int main() {
    int* ptr = new int(42); // 동적 메모리 할당
    // delete ptr; // 메모리를 해제하지 않음
    return 0;
}
  • 여기서 ptr이 가리키는 메모리를 해제하지 않으면, 프로그램 종료 시까지 해당 메모리는 계속 점유 상태로 남아 있습니다.
  • 프로그램이 종료되더라도 운영 체제는 누수를 감지하지 않고 메모리를 반환하지 않습니다.

2. 동적 메모리 누수가 발생하는 주요 이유

1) delete를 호출하지 않음

  • 할당된 메모리를 사용한 후, 개발자가 delete를 호출하지 않으면 메모리가 해제되지 않습니다.
  • 이 상황은 특히 예외 처리가 필요한 경우에서 흔히 발생합니다.

2) 포인터 재할당

  • 포인터를 새 메모리 주소로 재할당하기 전에 기존 메모리를 해제하지 않으면 메모리 누수가 발생합니다.
  • int* ptr = new int(42); ptr = new int(55); // 이전 메모리 주소를 잃어버림 delete ptr; // 새로 할당된 메모리만 해제

3) 포인터가 유효하지 않은 상태로 사라짐

  • 동적 메모리의 주소를 가리키던 포인터가 범위를 벗어나거나 덮어쓰기되면, 해당 메모리를 해제할 방법이 없어집니다.
  • void allocateMemory() { int* ptr = new int(42); // 함수 종료 시 ptr이 사라짐 → 메모리 누수 발생 }

4) 복잡한 데이터 구조

  • 동적으로 할당된 객체가 내부적으로 다른 동적 메모리를 참조하고 있을 때, 상위 객체만 해제하고 내부 객체를 해제하지 않으면 누수가 발생합니다.
  • class Node { int* value; Node(int v) { value = new int(v); } ~Node() { /* delete value; */ } // 내부 메모리를 해제하지 않음 };

5) 반복적 동적 할당

  • 반복문 내에서 동적 메모리를 할당하고 해제하지 않는 경우:
    for (int i = 0; i < 10; ++i) {
        int* ptr = new int(i);
        // delete ptr; // 생략됨 → 누수 발생
    }
    

3. 메모리 누수가 프로그램에 미치는 영향

  1. 메모리 부족:
    • 메모리를 계속 점유하고 해제하지 않으면, 프로그램이 사용하는 메모리가 증가하여 시스템 전체 성능이 저하됩니다.
  2. 프로그램 종료 시 문제:
    • 장시간 실행되는 서버 프로그램이나 게임에서는 메모리 누수가 쌓여 결국 시스템이 멈추거나 강제 종료될 수 있습니다.
  3. 디버깅 어려움:
    • 메모리 누수는 즉각적인 오류를 일으키지 않으므로, 문제가 발생한 위치를 추적하기가 어렵습니다.

4. 메모리 누수를 방지하는 방법

1) 할당과 해제를 한 쌍으로 관리

  • 메모리를 할당(new)한 경우, 항상 대응되는 delete를 호출해야 합니다.

2) 스마트 포인터 사용 (C++11 이상)

  • 스마트 포인터(std::unique_ptr, std::shared_ptr)를 사용하면, 소멸 시 자동으로 메모리를 해제합니다.
  • 예:
    #include <memory>
    
    std::unique_ptr<int> ptr(new int(42)); // 자동으로 메모리 관리
    

3) 코드 리뷰와 테스트

  • 코드 작성 후, 할당된 모든 메모리가 올바르게 해제되었는지 확인합니다.

4) 디버깅 툴 사용

  • Valgrind(Linux)나 Visual Studio Memory Profiler와 같은 메모리 디버깅 툴을 사용해 누수를 감지합니다.

5. 결론

동적 메모리 누수는 주로 delete를 생략하거나, 포인터가 유효한 범위를 벗어나는 상황에서 발생합니다. 이를 방지하려면:

  1. 항상 할당과 해제를 쌍으로 관리하고,
  2. 스마트 포인터와 같은 도구를 활용하며,
  3. 디버깅 툴로 정기적으로 메모리 상태를 점검해야 합니다.

메모리 관리는 C++에서 중요한 주제이며, 초기 단계부터 신경 쓰는 습관을 들이면 안전하고 효율적인 프로그램을 작성할 수 있습니다! 😊