시뻘건 개발 도전기

러스트 10 - Ownership : 소유권 #2 본문

프로그래밍/RUST

러스트 10 - Ownership : 소유권 #2

시뻘건볼때기 2019. 3. 2. 15:42
반응형

Rust Docs에 보면 다음과 같이 설명이 되어있다.


With the String type, in order to support a mutable, growable piece of text, we need to allocate an amount of memory on the heap, unknown at compile time, to hold the contents. This means:

    • The memory must be requested from the operating system at runtime.
    • We need a way of returning this memory to the operating system when we’re done with our String.


직역하면....


String type은 변경 가능한, 크기가 자유로운, text를 지원하기 위한 녀석인 것.

우리는 compile time에 알 수 없는 heap 영역의 메모리 공간 할당을 필요하다는 것.

    • 메모리는 runtime 때 OS로부터 요청 되어야 한다는 것.
    • 할 일을 다 한 String은 OS에게 메모리를 반환하는 방법이 필요하다는 것.


OS로 부터 요청이 되어야하는 메모리의 경우 이미 시도(?)해보았다.

String::from

지난 포스팅 <Ownership : 소유권 #1>에서 다루었다.(https://maeng-dev.tistory.com/13)

이 녀석을 사용하게 되면 from 구현체(Implementation)에서 필요한 메모리를 요구한다.


반대로, 메모리 반환의 경우에는 이야기가 다르다.

garbage collector(이하 gc)를 가진 언어의 경우, gc가 수시로 사용되지 않는 메모리를 찾아서 반환해준다.

하지만 rust의 경우 gc를 가지고 있지 않기 때문에 rust 개발자가 메모리 반환에 신경을 써야한다는 것이다.(반환해주는 코드 실행)

개발자도 사람인 것을.... 실수로 뺴먹었거나, 메모리 반환의 시점이 빠르거나 느리다면.... 메모리 낭비가 심해지거나  혹은 변수를 사용할 수 없게 될텐데...


이러한 이슈(issue)는 rust와는 성격이 다르다.!

메모리를 가진 변수가 scope를 벗어나면 메모리가 자동 반환된다.

이 부분은 마찬가지로 <Ownership : 소유권 #1>에서 다루었다.



scope를 벗어나게 되면 rust는 "drop"이라는 함수를 호출한다.(초록색 원으로 표시된 구간에서)

이 녀석은 String을 정의한 사람(개발자)이 메모리를 반환하는 코드를 넣을 수 있다. (어떻게..?)

drop의 경우에는 RAII(Resource Acquisition Is Initalization) 패턴을 알면 쉽게 이해할 수 있다고 한다....(이건 또 무엇?)






  1. 변수와 데이터가 상호작용 하는 방법

    1. move

    2. clone


  • move

다음 코드를 실행하면 어떤 현상이 일어날까?
fn main() {
    let str_1 = String::from("Memory");
    let str_2 = str_1;

    println!("str_1 : {}", str_1);
    println!("str_2 : {}", str_2);
}




에러 메시지만 봐도 알 수 있다. "str_1"의 value는 이동(move) 이후에 빌려(사용)오고 있다.

즉 str_1은 이미 move가 되었고 메모리에 value가 없다는 이야기.



메모리의 구조도 함께 살표보자.

※ ptr은 말 그대로 포인터. 즉 String이 있는 메모리의 주소.

※ length는 String의 내용이 현재 사용중인 바이트 단위의 메모리의 크기.

※ capacity는 추 후에 다시...





str_1을 str_2에 복사 하였을때는 아래 두 그림중 어느 쪽이 정답일까?



정답은 왼쪽.

String이 저장된 Heap 메모리의 주소를 동시에 가르키고 있다. 만약 Heap까지 복사해서 할당한다면(오른쪽) 어마어마하게 메모리를 낭비하게 될 것이다.

얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)라는 용어가 딱! 하고 떠올라야 한다. (무릎 팍!)

흔히 알고 있는 얕은 복사 개념이 move라고 보면 된다. 단, move는 첫 번째 변수를 무효화(Invalidates)한다.

scope 밖으로 벗어나면 rust가 메모리를 반환할 것이다.

만약 무효화되는지 모르고 반환을 하였다면 메모리를 두 번 반환(double free)를 하게 되고 이 것은 버그이며, 보안 취약성 문제를 야기시킨다고 한다.





  • clone

만약 Stack에 쌓인 String 데이터만 아닌, Heap 영역까지도 복사하고 싶다면? 그것이 바로 clone이다. (위 그림의 오른쪽 그림)

fn main() {
    let str_1 = String::from("Memory");
    let str_2 = str_1.clone();

    println!("str_1 : {}", str_1);
    println!("str_2 : {}", str_2);

}


같은 예제로 위 코드를 컴파일 해보자. 잘 출력이 될 것이다.









우리는 지금까지 Stack과 Heap을 한 번에 다루었다. (복잡복잡)

String은 Stack인데 내용은 Heap이라니? 이런....ㄷㄷ

java 공부할 때 [String str = new String();] 에서 equal(=)기준 왼쪽은 stack, 오른쪽은 Heap영역에 저장된다는 게 절로 떠올랐다.....ㅎㅎㅎ



반응형

'프로그래밍 > RUST' 카테고리의 다른 글

러스트 12 - 슬라이스 타입  (0) 2019.03.03
러스트 11 - References와 Borrowing  (0) 2019.03.02
러스트 9 - Ownership : 소유권 #1  (0) 2019.02.24
러스트 8 - 주석  (0) 2019.02.23
러스트 7 - 제어문과 반복문  (0) 2019.02.23
Comments