Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

메모리 누수(Memory leaks)

생성된 스레드에 참조를 전달할 때 가장 큰 걸림돌은 앞서 언급한 해제 후 사용(Use-after-free) 버그입니다. 이미 해제된 메모리 영역을 가리키는 포인터로 데이터에 접근하려 할 때 발생하죠.

만약 **힙 할당 데이터(Heap-allocated data)**를 다루고 있다면, Rust에게 “이 메모리는 다시 회수하지 않아도 돼“라고 알려줌으로써 이 문제를 회피할 수 있습니다. 즉, 의도적으로 **메모리 누수(Memory leaks)**를 발생시키는 것입니다.

Rust 표준 라이브러리의 Box::leak 메서드를 사용하면 이 작업을 수행할 수 있습니다.

// `u32` 값을 `Box`로 감싸 힙에 할당합니다.
let x = Box::new(41u32);

// `Box::leak`을 사용하여 이 힙 메모리를 절대 해제하지 않겠다고 Rust에게 알립니다.
// 그 결과로 프로그램 종료 시까지 유효한 `'static` 참조를 얻게 됩니다.
let static_ref: &'static mut u32 = Box::leak(x);

메모리 누수는 프로세스 단위로 관리됩니다

물론 메모리 누수는 기본적으로 위험한 일입니다. 메모리를 끊임없이 누수하다 보면 결국 시스템의 메모리가 바닥나 메모리 부족(Out of Memory, OOM) 오류로 프로그램이 강제 종료될 수 있습니다.

// 이 코드를 실행하면 결국 시스템의 사용 가능한 모든 메모리를 다 써버리게 됩니다.
fn oom_trigger() {
    loop {
        let v: Vec<usize> = Vec::with_capacity(1024);
        // 의도적으로 누수시킵니다.
        v.leak();
    }
}

하지만 leak 메서드로 누수시킨 메모리가 영원히 사라지는 것은 아닙니다. 운영 체제는 각 메모리 영역을 해당 프로세스에 매핑하여 관리하므로, 프로세스가 종료되는 순간 운영 체제는 해당 프로세스가 점유했던 모든 메모리를 자동으로 회수합니다.

이러한 점을 이용해 다음과 같은 상황에서는 메모리 누수를 전략적으로 활용하기도 합니다:

  • 누수되는 메모리의 양이 미리 정해져 있거나 충분히 작은 경우
  • 프로그램이 아주 짧은 시간만 실행되고 종료될 것이 확실한 경우

“운영 체제가 알아서 정리하게 둔다“는 전략은 상황에 따라 매우 효과적이고 유효한 메모리 관리 기법이 될 수 있습니다.

Exercise

The exercise for this section is located in 07_threads/03_leak