C/C++ 및 기타 저수준 언어에서는 개발자가 메모리에서 데이터의 배치를 명시적으로 관리해야 합니다: 스택(자동 변수) 또는 힙(malloc/new를 통한 할당). 이러한 언어에서는 메모리 누수, 이중 해제 또는 초기화되지 않았거나 이미 삭제된 메모리를 사용하여 오류가 자주 발생합니다. Rust는 가비지 컬렉터를 사용하지 않고 소유권 시스템을 통해 메모리 관리를 엄격하게 수행하는 역할을 맡습니다.
스택을 통한 자동 메모리 관리는 편리하지만 크기(스택 깊이)에 제한이 있습니다. 힙 할당은 리소스를 명시적으로 관리해야 하며, 이는 위험할 수 있습니다: 메모리를 해제하는 것을 잊거나 포인터의 생명 영역을 위반할 수 있습니다. 가비지 컬렉터는 항상 해결책이 아닙니다(자원 비용, 예측할 수 없는 중단). 메모리 관리 오류는 충돌 및 취약점을 초래합니다.
Rust에서 스택과 힙은 자동 관리로 구분됩니다: 모든 값은 기본적으로 스택에 배치되며, 동적 크기 또는 장기 사용 객체는 스마트 포인터(예: Box<T>, Vec<T>)를 통해 힙을 사용합니다. 소유권 및 대출 시스템은 소유권이 이전되거나 리소스의 생명 영역이 종료된 후 리소스가 자동으로 해제되도록 보장합니다. 이 모든 것은 컴파일 단계에서 보안을 보장하고 불필요한 가비지 컬렉터의 중단이 없도록 합니다.
코드 예시:
fn main() { let a = 42; // 스택 할당 let b = Box::new(42); // 힙 할당 let mut v = Vec::new(); v.push(1); v.push(2); // 배열 데이터는 힙에 }
주요 특징:
스택의 메모리를 수동으로 해제(dropping)할 수 있나요?
아니요. 스택에 할당된 변수의 해제는 범위를 벗어날 때 자동으로 발생하며, 수동으로 drop을 수행하는 것은 무의미하며 스택 포인터의 경우 허용되지 않습니다.
이동(move)은 힙으로 이동(In-place allocation)하나요?
아니요. 변수의 소유자 간 이동은 반드시 힙으로 이동하는 것이 아니며, 소유권만 변경됩니다.
Box<T>를 사용한다고 해서 T가 항상 힙에 있나요?
네, Box<T>는 실제로 T를 힙에 할당하지만, 소유권과 생명 영역은 여전히 엄격하게 관리됩니다.
프로젝트에서 수동 메모리 관리를 위해 mem::forget 또는 drop을 통해 글로벌 vector(Vec<T>)를 사용하여 때때로 해제된 메모리에 대한 유령 포인터가 남아 있습니다.
장점:
단점:
객체를 명시적으로 Box를 통해 배치하고, 데이터 전송은 소유권 규칙에 따라 진행하며, 컬렉션에 대해 스마트 포인터를 사용하고 스택 변수를 가리키지 않는 방식입니다.
장점:
단점: