프로그래밍/Rust

[Rust] Stack과 Heap (번역)

Lou Park 2023. 5. 14. 22:32

Stack과 Heap

많은 프로그래밍 언어에서는 스택(Stack)과 힙(Heap)에 대해 자주 생각할 필요가 없다. 그러나 시스템 프로그래밍 언어인 Rust에서는 값이 스택에 있거나 힙에 있는지 여부가 언어의 동작 방식과 특정 결정을 내리는 이유에 영향을 미친다. 

 

Stack

스택에 대하여

스택과 힙은 모두 런타임(Runtime)에 코드가 사용할 수 있는 메모리의 일부이지만 구조가 다르다. 

스택은 값을 가져온 순서대로 저장하고 반대 순서로 값을 제거한다. 이것을 "Last In, First Out" (LIFO)라고 한다. 접시 더미를 생각해보라. 접시를 더 추가하면 더미 위에 놓고 접시가 필요할 때는 가장 위에서 하나씩 가져온다. 중간이나 바닥에서 접시를 추가하거나 제거하는 것은 그다지 효과적이지 않을 것이다. 데이터를 추가하는 것을 스택에 "Push"라고 하고, 데이터를 제거하는 것을 스택에서 "Pop"이라고 한다. 스택에 저장된 모든 데이터는 알려진 고정된 크기여야한다. 가령 연결 리스트(Linked List)처럼 컴파일 타임에 크기가 알려지지 않았거나 크기가 변경될 수 있는 데이터는 힙에 저장해야한다.

 

힙에 대하여

힙은 덜 정리되어 있다. 힙에 데이터를 저장하면 특정 크기의 공간을 요청한다. 메모리 할당자는 힙의 빈 공간을 찾아 충분히 크고 사용 중임을 표시하고 해당 위치의 주소인 포인터(Pointer)를 반환한다. 이 프로세스를 "힙에 할당(allocate)"한다 라고 하며 때때로 할당(Allocating)이라고만 축약한다. (스택에 값을 푸시하는 것은 할당이 아니다). 힙에 대한 포인터는 알려진 고정된 크기이므로 스택에 저장할 수 있지만 실제 데이터를 원할 때는 포인터를 따라가야한다. 식당에와서 자리에 앉을때를 생각해보라. 입장할때 몇 명인지 얘기하고 식당 주인은 모든 사람들이 들어갈 수 있는 빈 테이블을 찾아서 안내한다. 그리고 그룹에서 누군가 늦게 도착하면 식당 주인에게 어디에 앉았는지 물어봐서 찾을 수 있다.

 

속도 측면에서의 스택과 힙의 비교

스택에 푸시하는 것은 힙에 할당하는 것보다 빠르다. 할당자는 새 데이터를 저장할 장소를 찾을 필요가 없기 때문이다. 그 위치는 항상 스택의 맨 위에 있다. 반면에 힙에 공간을 할당하는 것은 할당자 먼저 데이터를 저장할 수 있을 만큼 큰 공간을 찾은 다음 할당을 준비하기 위해 책무를 수행해야 하므로 더 많은 작업이 필요하다.

힙의 데이터에 액세스하는 것은 스택의 데이터에 액세스하는 것보다 느리다. 포인터를 따라가야하기 때문이다. 현대 프로세서는 메모리에서 덜 이동하면 더욱 빠르다. 아까 식당 비유를 계속하자면, 많은 테이블에서 주문을 받는 식당 알바생을 생각해보라. 한 테이블에서 모든 주문을 받고 다음 테이블로 넘어가는 것이 가장 효율적이다. A 테이블에서 주문을 한다음 B에서 주문을하고, 다시 A에서 하고 또 B에서 다시주문하는 것은 비효율적이다. 마찬가지로 프로세서는 스택에 있는 것처럼 다른 데이터와 가장 가까운 데이터에서 작업하는 경우 더 나은 작업을 수행할 수 있다.

 

코드가 함수를 호출하면 함수에 전달된 값(잠재적으로 힙에 있는 데이터에 대한 포인터 포함)과 함수의 지역 변수가 스택에 푸시된다. 함수가 끝나면 해당 값이 스택에서 팝 된다. 

 

소유권

Rust의 소유권(Ownership)개념은 스택과 힙에서 어떤 코드 부분이 어떤 데이터를 사용하고 있는지 추적하고, 힙에서 중복 데이터의 양을 최소화하고, 힙에서 사용되지 않는 데이터를 정리하여 공간 부족을 방지하는 모든 문제를 해결한다. 소유권을 이해하면 스택과 힙에 대해 자주 생각할 필요는 없지만 소유권의 주된 목적이 힙 데이터를 관리하는 것이므로 그것이 작동하는 방식을 설명하는데 도움이 될 수 있다.

 

 

원문 https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html