Rust RAII 자원 관리

Beginner

This tutorial is from open-source community. Access the source code

소개

이 랩에서는 Rust 의 RAII (Resource Acquisition Is Initialization, 자원 획득은 초기화) 개념을 탐구합니다. 이는 객체가 스코프를 벗어날 때 소멸자가 호출되고 소유된 자원이 해제되어 수동 메모리 관리가 필요 없고 자원 누수 버그로부터 보호됨을 의미합니다. 또한, 사용자 정의 소멸자 로직을 필요로 하는 타입에 대해 구현할 수 있도록 해주는 Rust 의 Drop 트레이트에 대해서도 배우겠습니다.

참고: 랩에서 파일 이름을 지정하지 않은 경우, 원하는 파일 이름을 사용할 수 있습니다. 예를 들어, main.rs를 사용하고 rustc main.rs && ./main으로 컴파일하고 실행할 수 있습니다.

RAII (자원 획득은 초기화)

Rust 의 변수는 스택에 데이터를 저장하는 것 이상으로, 자원을 소유합니다. 예를 들어, Box<T>는 힙의 메모리를 소유합니다. Rust 는 RAII (Resource Acquisition Is Initialization, 자원 획득은 초기화) 를 적용하므로, 객체가 스코프를 벗어날 때마다 소멸자가 호출되고 소유된 자원이 해제됩니다.

이 동작은 자원 누수 버그로부터 보호하므로, 더 이상 수동으로 메모리를 해제하거나 메모리 누수에 대해 걱정할 필요가 없습니다! 다음은 간단한 예시입니다:

// raii.rs
fn create_box() {
    // 힙에 정수를 할당합니다.
    let _box1 = Box::new(3i32);

    // `_box1` 은 여기서 파괴되고 메모리가 해제됩니다.
}

fn main() {
    // 힙에 정수를 할당합니다.
    let _box2 = Box::new(5i32);

    // 중첩된 스코프:
    {
        // 힙에 정수를 할당합니다.
        let _box3 = Box::new(4i32);

        // `_box3` 은 여기서 파괴되고 메모리가 해제됩니다.
    }

    // 재미로 많은 박스를 생성합니다.
    // 수동으로 메모리를 해제할 필요가 없습니다!
    for _ in 0u32..1_000 {
        create_box();
    }

    // `_box2` 는 여기서 파괴되고 메모리가 해제됩니다.
}

물론, valgrind를 사용하여 메모리 오류를 다시 확인할 수 있습니다:

$ rustc raii.rs && valgrind ./raii
==26873== Memcheck, a memory error detector
==26873== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==26873== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==26873== Command: ./raii
==26873==
==26873==
==26873== HEAP SUMMARY:
==26873==     in use at exit: 0 bytes in 0 blocks
==26873==   total heap usage: 1,013 allocs, 1,013 frees, 8,696 bytes allocated
==26873==
==26873== All heap blocks were freed -- no leaks are possible
==26873==
==26873== For counts of detected and suppressed errors, rerun with: -v
==26873== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

여기에는 누수가 없습니다!

소멸자

Rust 에서 소멸자의 개념은 [Drop] 트레이트를 통해 제공됩니다. 소멸자는 자원이 스코프를 벗어날 때 호출됩니다. 이 트레이트는 모든 타입에 대해 구현할 필요는 없으며, 자체 소멸자 로직이 필요한 경우에만 타입을 위해 구현합니다.

아래 예제를 실행하여 [Drop] 트레이트가 어떻게 작동하는지 확인하십시오. main 함수의 변수가 스코프를 벗어날 때 사용자 정의 소멸자가 호출됩니다.

struct ToDrop;

impl Drop for ToDrop {
    fn drop(&mut self) {
        println!("ToDrop is being dropped");
    }
}

fn main() {
    let x = ToDrop;
    println!("Made a ToDrop!");
}

요약

축하합니다! RAII 랩을 완료했습니다. LabEx 에서 더 많은 랩을 연습하여 실력을 향상시킬 수 있습니다.