메모리 구조
우리가 흔히 사용하는 프로그램들을 실행하려면 프로그램이 메모리(RAM) 위에 올라가야 한다. 또한 프로그램 내의 여러 변수를 저장하기 위한 메모리 공간이 필요한데 이 부분을 오늘 다뤄볼 것이다.
통상적으로 알고 있는 메모리 구조의 네 가지인, 코드(Code), 데이터(Data), 힙(Heap), 스택(Stack)에 대해서 하나하나 알아보자.
Code
말 그대로 코드 영역은, 실행할 프로그램의 코드가 저장되는 장소이다. 텍스트 영역이라고도 하나, 주로 코드 영역이라고 부른다.
코드는 우리가 읽을 수 있는 형태가 아닌, 기계어로 저장된다. 또한 프로그램 실행에 필요한 코드들이기 때문에 프로그램 실행 ~ 끝까지 메모리에 존재한다. 그리고 코드 영역은 컴파일 타임에 결정되어 저장된다. 또한 프로그램 실행 도중에 우리가 작성한 코드가 변경되는 불상사가 생기면 안되기 때문에 읽기만 가능하다.
- 실행할 프로그램의 코드를 저장, 코드는 기계어로 저장
- 프로그램 실행부터 끝까지 메모리에 존재
- 컴파일 타임에 결정
- Read-Only
Data
데이터 영역에는 전역(global) 변수와, 정적(static) 변수가 저장된다. 이 또한 프로그램이 실행되고 끝날 때 까지 메모리에 존재한다. 코드영역과 같이 프로그램이 종료되어야 메모리가 해제된다!
var globalVariable = "global" // 전역 변수
struct Game {
static let title: String // 정적 변수
}
- 프로그램 실행부터 끝까지 메모리에 존재
- 전역 변수, 정적 변수 저장
- Read-Write
Heap
힙 영역은 "사용자가 동적으로 할당할 수 있는 공간"이다. 즉 컴파일 타임이 아닌, 런타임에 그 크기가 정해진다. 위의 그림에서 보이는 것 처럼 힙 영역은 낮은 메모리 주소에서 높은 메모리 주소 방향으로 메모리를 차지하게 된다. 또한 스택과 메모리 공간을 공유하기 때문에 힙 영역이 커지면 스택 영역이 작아지고, 힙 영역이 작아지면 스택 영역이 커진다. 이러한 두 가지 경우를 다음과 같이 부른다.
- 스택오버플로우(Stack Overflow) : 스택 영역 > 힙 영역 (스택 영역이 힙 영역을 침범하는 경우)
- 힙오버플로우(Heap Overflow) : 스택 영역 < 힙 영역 (힙 영역이 스택 영역을 침범하는 경우)
(우리가 구글링하며 많이 찾고 참고하던 스택오버플로우 사이트의 이름이 여기서 유래되었다는 것을 일 수 있다..)
아무튼! 런타임에 메모리 할당하고 해제하는 작업이 필요한데, Swift에서는 ARC라는 강력한 기능을 제공하여 메모리 해제 작업을 돕는다. ARC는 추후에 더 자세하게 알아보자.
또한 힙 영역에는 클래스 인스턴스나 클로저 같은 참조타입(Reference type)이 저장된다.
class Food {
var name: String
var price: Int
}
var chicken: Food = Food() // 클래스 인스턴스
var getPrice: (() -> ())? // 클로져
- 데이터나 프로그램의 크기를 미리 알 수 없는 경우, 스택에 저장하기에 너무 큰 경우 힙 영역에 저장 (= 메모리 크기 제한이 없음)
- 메모리 할당/해제 작업으로 인한 속도 저하 (= 메모리를 직접 관리해줘야 함)
- 힙 경합(두 개의 쓰레드에서 동시에 데이터에 접근하려고 하는 경우 경합이 발생)으로 인한 속도 저하
- 힙 손상(해제 후 사용, 덮어쓰기 등)으로 인한 속도 저하
Stack
스택 영역은 컴파일 타임에 크기가 결정되는 영역이며, 주로 지역 변수나 매개 변수, 반환값 등을 저장한다. 스택 영역에 저장되는 함수의 호출 정보를 "스택 프레임(Stack Frame)"이라고 부른다.
func sell(_ price: Int, _ amount: Int) -> Int { // 매개 변수 : price, amount
let profit = price * amount // 지역 변수 : profit
return profit
}
컴파일 타임에 결정되다 보니, 힙 영역과 달리 동적으로 할당/해제를 해줄 수 없으며, 함수가 실행되면 스택 영역에 올라오게 되고, 함수가 종료되면 그 함수 내의 매개변수,지역변수 등이 해제된다. 즉 함수의 실행/종료에 따라 메모리의 할당/해제 또한 정해진다.
또한 CPU에 의해 관리되어 힙 영역에 비해 빠른 속도를 가진다는 것이 장점이다.
그리고 앞서 봤듯이 힙 영역이 낮은 메모리 주소에서 높은 메모리 주소 방향으로 메모리를 차지하였다면, 스택 영역은 높은 메모리 주소에서 낮은 메모리 주소 방향으로 메모리를 차지하게 된다. 그러면서 아까 봤던, 스택/힙 오버플로우가 발생하게 되는 것이다. 추가적으로 힙 영역과는 달리 스택 영역은 메모리 크기 제한이 있어서 이에 유념하여 사용해야 한다.
또한 스택은 힙 영역보다 할당 속도가 빠르다. 왜냐하면, 스택은 이미 할당된 공간을 사용하는 것이고, 힙은 따로 할당하여 사용해야하기 때문이다.
- CPU가 관리하여 속도가 빠르다
- 메모리를 직접 해제하지 않아도 된다.
- 메모리 크기에 제한이 있다.
Ref :
https://rolypolytoy.tistory.com/29
https://babbab2.tistory.com/25