OWNERSHIP

값에는 한 명의 소유자만 있다

Rust는 실행 중 GC 없이도 메모리를 안전하게 정리한다. 컴파일러가 소유자, 이동, 스코프 종료 지점을 미리 검사하기 때문이다.

Owner 각 값의 소유자는 하나
Move 힙 데이터는 옮겨 쓰기
Drop 스코프 끝에서 정리
규칙 1 각 값은 owner를 가진다
규칙 2 owner는 동시에 하나뿐이다
규칙 3 owner가 끝나면 값도 drop

String 이동은 힙 복사가 아니다

let s2 = s1; 이후 힙 버퍼의 소유자는 s2가 되고, s1은 더 이상 사용할 수 없다.

Stack

metadata
s1
ptr moved
len/cap 사용 불가
s2
ptr 0xA0
len/cap 5 / 5

Heap

buffer
0xA0 owned by s2
h e l l o

왜 s1을 막는가

같은 힙 주소를 두 변수가 해제하면 double free가 되므로, 이전 소유자를 무효화한다.

위험 같은 주소를 두 번 해제

s1과 s2가 모두 유효하면 스코프 끝에서 같은 힙 버퍼를 중복 해제할 수 있다.

검사 컴파일 타임 차단

이동 후 s1 사용은 실행 전에 오류가 된다. 런타임 비용 없이 규칙을 지킨다.

정리 drop은 한 번만

마지막 소유자인 s2가 스코프를 벗어날 때 힙 메모리가 정리된다.

대입이 항상 같은 의미는 아니다

스택 값은 Copy, 힙 소유 값은 Move, 명시 복사는 Clone으로 구분한다.

Copy

작고 고정된 값

정수처럼 스택에 담기는 단순 값은 복사 후 두 변수 모두 유효하다.

let x = 5;
let y = x;  // x도 유효
Move

힙 소유권 이동

String은 포인터 메타데이터만 이동하고 기존 변수 사용을 막는다.

let s1 = String::from("hi");
let s2 = s1; // s1 무효
Clone

힙 데이터까지 복사

두 버퍼가 모두 필요하면 의도를 드러내며 깊은 복사를 요청한다.

let s2 = s1.clone();
// s1, s2 모두 유효

소유권 생명주기

값은 생성, 이동, 사용, 스코프 종료라는 흐름 안에서 관리된다.

create 값 생성 String::from이 힙 버퍼를 확보한다.
own 소유자 지정 처음에는 s1이 버퍼를 책임진다.
move 소유권 이동 s2 = s1 뒤에는 s2만 유효하다.
drop 자동 해제 스코프 끝에서 소유자가 가진 리소스를 정리한다.