-
[Rust] 4. ownership(1). ownership, 변수와 ownershiprust 2023. 1. 28. 10:37반응형
https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
정리하는글이다.
메모리관리
- 명시적 할당 및 해제
- garbage collector
- ownership 개념을 통해 compile time에 방지(rust에서의 메모리관리)
스택과 힙
- 런타임에 사용할수 있는 메모리 공간의 종류 이며 각기 다른 방식으로 구조화 되어있다.
- value 는 스택이나 힙에 저장되며 어디에 저장 되느냐에 따라 동작방식에 영향을 준다.
- 컴파일 타임에 크기가 유동적이거나 정해지지않은 경우 데이터는 힙에 저장 되며 그외의 경우는 스택에 저장된다.
- 스택에 저장할수 있는 데이터는 항상 스택의 top 위치에 저장한다.
- 힙에 저장해야하는 데이터는 힙 안의 빈지점을 찾아 저장(할당)하고 지점의 포인터를 스택에 푸시 한다.
- 따라서 데이터 접근시 힙의 경우 포인터를 따라가야 하며 저장시에도 할당할수 있는 공간을 찾는과정(allocating on the heap)는 과정은 작업을 느리게 하는 요소이다.
- 그렇기 때문에 memory leak 의 주요 원인은 힙을 잘 관리 하지 못한경우에 일어난다.
- 힙내의 중복된 데이터의 양을 최소화 하고, 사용하지 않는 데이터를 제거 하는것이 memory 를 관리한다 라고 할수있다.
Ownership Rule
- value 는 owner 로 불리는 variable을 가지고 있다.
- value의 owner에 해당하는 variable 은 하나만 존재한다.
- owner 에 해당하는 varialble 이 scope 을 벗어나면 value는 drop 된다.
이때 scope 은 variable 의 선언 시점부터 괄호가 끝나는 지점 까지를 이야기 하며 rust는 괄호가 끝나면 자동적으로 drop 이라는 함수를 호출하여 필요한 작업을 진행한다.
이부분이 rust의 특징인데 다른 언어는 gc 를 이용해서 사용하지 않는 메모리를 비워 주거나 명시적으로 allocate 와 free 를 해줘야 하지만 rust는 scope 을 벗어나면 자동으로 반납하게 된다.
변수와 Ownership
String type은 힙에 저장될 좋은 예시이며 주의할 점은 &str(스트링 리터럴) 과는 다른 타입이라는 점이다.
기본적인 차이는 &str 의 경우 고정된 크기이며 Immutable 하다. 그러나 String 의 경우는 compile time 이 아닌 runtime 에 크기가 정해지며 mutable 하다. 그렇기 때문에 String 은 heap에 저장되며 &str 은 스택에 저장된다.
> move
- value의 owner에 해당하는 variable 은 하나만 존재한다.
ownership rule 의 2번째에 해당하는 내용이며 이 rule에서 발생하는 특징이다. 예시를 보자
let x = 5; let y = x; let s1 = String::from("hello"); let s2 = s1;
구조적으로 동일하지만 둘의 차이는 5는 stack 에 저장 되지만 String::from("hello") 를 heap에 저장된다는 차이가 있다.
스택에 저장된 데이터는 x 의 값을 복사하여 y에 할당하지만 힙에 저장된 데이터의 경우 힙을 통째로 복사하지 않는다.
대신 힙을 가리키는 포인터만 복사하고 가지고 할당하게 된다. 그렇게 되면 s1 과 s2 의 포인터는 같은 위치를 가리키게 된다.
이는 다른 언어에서 는 shallow copy 를 통한 참조형 자료의 관리 방법과 같아보인다.
그러나 rust 에서는 scope 에서 벗어나게 되는 경우 같은 메모리 공간은 두번 drop 하게되므로 이는 double free 오류를 유발하여 메모리 손상의 원인이 될수 있다.
그렇기 때문에 rust 에서는 힙에 저장한 s1의 값을 s2 에 할당하는 경우 s1은 더이상 유효하지 않다고 간주 하게 되는데
이는 value 의 owner 에 해당하는 variable은 하나만 존재한다는 원칙을 떠올리게한다. 이러한 특징을 move 라고 한다.
> clone
힙데이터를 s2 에 할당한 이후에도 s1 역시 유효하게 사용하고 싶은 경우에는 힙 자체를 복사해서 s2 에 할당해줄수도 있는데 그럴때는 공용 메소드인 clone 을 사용할수 있다. 이때는 같은 value 를 하나더 만든다고 생각하면 된다.
let s1 = String::from("hello"); let s2 = s1.clone(); println!("s1 = {}, s2 = {}", s1, s2);
스택데이터는 clone 하지 않더라도 빠르게 복사본이 만들어 질수 있는데 이과정은 copy라고 부른다.
느낀점
음.. 새로운 개념이기는 한데 되게 직관적이고 달라서 그렇지 어려운 개념은 아니라고 느꼇다.
변화는 작으면서 효과는 되게 큰 방법을 고려한거 같다.
그리고 변화에서 나오는 오류들도 runtime에서 나올에러가 아니라 compile time 에서 발견이 가능하게 되어있어서 번거로울수는 있어도 안정성이 되게 높은거 같다 그래서 안전한 언어라고 했구나~~ 싶었다.
'rust' 카테고리의 다른 글
[Rust] 4.ownership(3). slice (0) 2023.01.28 [Rust] 4. ownership(2).함수와 ownership (0) 2023.01.28 [Rust] 3. 변수, 데이터타입 (0) 2023.01.26 [Rust] 2.programing guessing game (0) 2023.01.25 [Rust] 1.getting started (1) 2023.01.25