Rust에서는 모든 값이 고유의 소유권을 갖는다. 이 소유권 개념은 메모리 안전성을 확보하기 위해 설계된 핵심 메커니즘이다. 소유권 규칙은 값이 어떻게 생성, 이동, 해제되는지를 정의하며 컴파일 타임에 메모리 관련 오류를 효과적으로 방지한다. 특히 러스트는 개발자가 명시적으로 메모리를 해제할 필요 없이, 스코프를 벗어날 때 자동으로 자원을 정리한다. 이 과정에서 잘못된 메모리 접근이나 이중 해제(double free)와 같은 오류가 발생하지 않도록 엄격한 규칙을 적용한다.
러스트에서 소유권은 한 시점에 단 하나의 소유자만 존재한다는 점이 중요하다. 이 말은 어떤 변수를 다른 변수에 대입하거나 함수를 통해 값을 전달할 때, 이전 소유자에게서 소유권이 새로운 대상으로 이동(moving)한다는 것을 의미한다. 소유권이 이동한 뒤에는 원래 소유자는 더 이상 그 값을 유효하게 사용할 수 없다. 이런 방식을 통해 같은 데이터를 동시에 여러 곳에서 무분별하게 해제하거나 수정할 가능성을 미리 차단한다.
예를 들어 String 타입의 값이 어떻게 이동하는지 살펴보면 아래와 같다.
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1의 소유권이 s2로 이동
// println!("{}", s1); // 컴파일 에러: s1은 더 이상 유효하지 않음
println!("{}", s2);
}
s1이 문자열 "hello"에 대한 힙 메모리를 소유하던 중, s2가 s1을 대입받는 순간 소유권이 s2로 넘어간다. 이때 컴파일러는 s1을 무효 처리하여 이후에 s1을 사용하려고 하면 에러를 발생시킨다. 이는 Rust가 동일 메모리를 가리키는 두 개 이상의 소유자를 허용하지 않는다는 증거이기도 하다.
만약 동일한 데이터를 독립적으로 복제하고자 한다면 clone 메서드를 사용할 수 있다. clone 메서드는 힙에 있는 실제 데이터까지 새로 복사하므로, 이후에도 원본과 복사본이 각각 자기만의 소유권을 갖게 된다.
fn main() {
let s1 = String::from("hello");
let s2 = s1.clone(); // s1 데이터를 힙 영역까지 복제
println!("s1: {}, s2: {}", s1, s2);
}
이 예시에서는 s1과 s2가 서로 다른 메모리에 "hello"라는 복사본을 가지고 있으므로 둘 다 유효하게 사용할 수 있다. 다만 이 경우 메모리 복제 비용이 발생하므로, 지나치게 빈번한 clone 사용은 성능에 영향을 줄 수 있다는 점에 유의해야 한다.
러스트의 소유권 규칙은 변수가 유효 범위(scope)를 벗어나는 순간 drop 함수를 통해 자동으로 할당 해제를 수행하게 만든다. 스택(stack)에 저장되는 정수나 불리언 등은 사용이 끝나면 스코프 종료 시점에 자연스럽게 정리되며, 힙(heap)에 저장되는 데이터 구조(String, Vec, Box 등) 또한 스코프가 닫힐 때 자동으로 메모리를 반납한다. 이러한 동작은 RAII(Resource Acquisition Is Initialization) 원칙에 기반하며, 매번 명시적 해제를 요구하지 않기 때문에 안전성과 편의성을 동시에 확보한다.
소유권 규칙은 러스트의 빌림(Borrowing)과도 긴밀하게 연결된다. 소유권이 없는 단순 참조(immutable reference)나 가변 참조(mutable reference)를 사용하는 것은, 본래의 소유자가 존재한다는 전제하에서만 가능하다. 단 하나의 가변 참조만 허용되거나, 여러 개의 불변 참조만 허용되는 제한은 메모리 안정성을 보장하기 위한 핵심 규칙이다. 소유권 시스템은 이러한 참조 관계가 안전하게 구성되어 있는지 컴파일 시점에서 확인하며, 잘못된 참조가 일어날 수 있는 상황을 원천 봉쇄한다.
정리하자면 러스트에서 소유권은 메모리 관리의 중심 축이고, 한 시점에는 정확히 하나의 소유자만이 존재한다. 소유자가 스코프를 벗어나면 그 시점에 대응되는 자원은 안전하게 해제된다. 소유권을 다른 변수로 이동하면 원래 소유자는 해당 자원에 대한 접근 권한을 상실한다. clone 메서드를 사용하면 힙 데이터를 복제할 수 있지만, 이에 따른 성능 비용을 고려해야 한다. 이러한 소유권 규칙을 기반으로, 러스트는 메모리 안정성과 성능을 모두 놓치지 않는 언어로 자리매김하고 있다.