본문 바로가기
Rust

Rust 메모리관리와 Ownership

by 올리고당 2021. 6. 16.

목차


Ownership ( 소유권 ) 등장 배경

동적 할당으로 인한 메모리 누수 문제를 다른 언어에서는 다음과 같이 대응했습니다.

C/C++ : "메모리 관리, 그거 프로그래머 실력이야!"
Java, Python 등 : "성능이고 나발이고 우린 Garbage Collector 쓸래."

 

C/C++에서는 문제를 방관했고, Java는 성능을 어느 정도 포기하고 개발의 편리함을 선택했습니다.

하지만 Rust에서는 조금 다른 방식으로 접근했습니다.

Rust : "동적 할당 변수도 지역변수처럼 사용하면 메모리 누수 문제를 해결할 수 있지 않을까?"

 

이처럼, Rust는 안전한 메모리 사용과 성능, 이 두 마리 토끼를 잡기 위해 GC를 선택하지 않고, C/C++ 보다 엄격한 컴파일러 규칙으로 메모리 누수 문제를 해결하려고 접근했습니다. 컴파일러 규칙으로 C++ RAII 패턴(메모리를 할당한 지역을 벗어나면 메모리의 할당을 해제)을 강제로 적용했습니다.

 

언뜻 들어보면, 간단히 문제가 해결될 것 같지만, 새로운 문제가 발생합니다. 문제를 살펴보기 앞서, 기존 프로그래밍 언어에서 다루는 데이터 복사 방식을 다시 한번 짚고 넘어가겠습니다.

 

  • Deep Copy      ( 깊은 복사 ) : 크기가 한정된 작은 데이터
  • Shallow Copy ( 얕은 복사 ) : 리스트나 객체 등 주로 크기가 큰 데이터
Deep Copy Shallow Copy
 

 

Rust에서는 동적 할당 변수를 복사할 때, 어떻게 처리할까요?

 

복사 예시 코드

※ String 객체는 컴파일 타임에 정확한 크기를 알 수 없어 heap영역에 할당됨.

 

heap 메모리 영역의 변수들을 Deep Copy 하면 프로그램의 속도 저하가 심각해지기 때문에, 다른 언어와 마찬가지로 RustShallow Copy를 선택해야 했습니다. 다만, 위에서 말씀드린 새로운 문제가 여기서 발생합니다. 두 포인터가 같은 데이터를 가리키고 있으므로, 같은 메모리 영역에 대해 메모리 할당 해제를 두 번 하게 되는 것이죠! 이 문제를 해결하기 위해 등장한 개념이 바로 Ownership ( 소유권 )입니다.

 


Ownership ( 소유권 ) 동작원리

Ownership ( 소유권 )이 무엇일까요?

Ownership ( 소유권 )은 단어 의미 그대로, '데이터를 소유할 권리를 어떤 포인터가 가지고 있냐'를 나타냅니다.

Rust에서는 어떤 데이터에 대한 Ownership( 소유권 )은 하나의 포인터만이 가질 수 있습니다. 따라서, 위의 복사 예시 코드에서는 Move( 소유권 이동 )이 발생합니다.

 

데이터 소유(s1) 같은 데이터 가리킴 소유권 이동(s1->s2)

※ 위에서 이야기할 때에는 Shallow Copy라고 말씀드렸지만 엄밀이 따져보면 다른 방식이므로, Rust에서는 Shallow Copy라고 부르기보다는 Move ( 소유권 이동 )이라고 합니다.

 

Move ( 소유권 이동 )이 아닌 Deep Copy를 하려면 어떻게 해야 할까요?

 

Deep Copy 예시 코드

위의 예시 코드처럼 clone( ) 멤버 함수를 호출해주시면 됩니다. 다만, 메모리 용량이 큰 데이터를 복사하실 때, 프로그램의 속도가 저하되는 것을 염두하시고 사용하시길 바랍니다.

 


모든 변수에서 Ownership Move ( 소유권 이동 )이 발생할까?

아닙니다. 컴파일 타임에 크기를 알 수 있는 변수들은 stack에 저장되고, stack에 저장되는 이 변수들은 copy trait ( 복사 특성 )을 가집니다. 대입 연산 시, copy trait을 가진 변수들은 Move ( 소유권 이동 )이 아닌 Deep Copy를 합니다.

 

그럼 copy trait( 복사 특성 )을 가진 변수 타입은 무엇일까요?

 

  • integer type 변수 ( i32, u32,... )
  • bool type 변수
  • floating point type 변수 ( f32, f64 )
  • char type 변수
  • 직접 쓰인 String 변수 ( ex. let s = "hello" )
  • copy trait의 변수 타입인 element만을 가진 tuple ( 튜플 )
  • copy trait의 변수 타입의 array ( 배열 )

 

copy trait의 변수 타입 Tuple과 Array 예시 코드


Ownership ( 소유권 )과 함수

그럼 함수 매개변수와 반환 값에서의 Ownership ( 소유권 ) 관계는 어떻게 될까요?

함수 내부에서의 Ownership ( 소유권 ) 동작원리와 동일합니다.

 

함수 매개변수와 반환 값 Ownership 예시 코드

 


공식 도서

https://doc.rust-lang.org/book/

 

공식 도서 번역본

https://rinthel.github.io/rust-lang-book-ko/

 


오늘은 Rust 메모리 관리와 Ownership에 대해 정리해보았습니다.

저도 정리하면서 공부할 수 있는 좋은 시간이었습니다.

여러분께도 조금이나마 도움이 되었으면 좋겠습니다.

감사합니다.

 

* 피드백은 댓글로 남겨주세요 *