[iOS] 메모리 구조

 이번 글에서는 개발자가 작성하는 코드가 메모리에서 어떤 부분에 저장되는지 알아보려고 한다.

 

메모리 구조

메모리 구조

프로그램이 실행되면 운영체제(OS)는 메모리(RAM)에 프로그램을 위한 공간을 할당해 준다.

공간은 총 4가지(코드, 데이터, 힙, 스택)의 공간으로 나눠져 있다.

 

빌드를 통해 실행파일로 만들면, OS는 정보를 파악하여 메모리 공간에 할당하고

그 이후, OS는 코드를 읽고 쓰며 동작을 시작하게 된다.

 

그럼 하나하나 짚고 넘어가 보자!

 

 

코드(Code) 영역

 

우리가 작성한 소스 코드는 기계어 형태로 저장이 된다.

컴파일 타임에 결정되며, 중간에 코드가 변경되지 않도록 Read-Only 형태로 저장된다.

 

 

 

 

데이터(Data) 영역

 

전역변수, static 변수, 상수, 타입 메타데이터 등이 저장되는 곳이다.

프로그램 시작과 동시에 할당되며, 프로그램이 종료되면 해제된다.

코드 영역과의 차이는 실행 도중 변경될 수 있다는 점이다. (Read-Write)

var name: String = "Greed" //전역 변수로 데이터 영역에 할당
var age: Int = 20

struct Nationality {
	static let country = "Korea" //스태틱 변수(상수)로 데이터 영역에 할당
}

 

그러나 swift에서 static은 기본적으로 lazy로 동작된다고 한다.

G**에 따르면 swift에서는 static 변수에 처음 접근할 때 초기화되며

이때 데이터 영역에 할당된다고 한다.

 

 

 

힙(Heap) 영역

 

프로그래머가 할당/해제하는 메모리 영역이다.

프로그래머는 malloc, calloc으로 힙에 메모리를 할당할 수 있는데 이를 '동적 할당'이라고 한다.

 

사용하고 난 후에는 반드시 메모리 해제를 해줘야 하며,

그렇지 않으면 메모리 누수(memory leak)가 발생한다.

 

4개의 영역 중 유일하게 런타임 시 결정되기에 데이터 크기가 확실하지 않을 때 사용한다.

 

 

중요한 만큼 설명할 부분도 많다. 간단하게 예제를 통해 알아보자.

class Movie {
    let name: String
    let genre: String
    
    init(name: String, genre: String) {
        self.name = name
        self.genre = genre
    }
}

let movie = Movie(name: "Inception", genre: "Science Fiction") //인스턴스를 힙 영역에 할당

 

위의 코드와 같이 클래스 인스턴스나 클로저 같은 참조 타입의 값을

런타임 시점에 자동으로 할당하고 있었다.

 

그렇다면 사용하고 난 후에 메모리 해제를 해줘야 한다고 했는데
생각해 보면 메모리 해제를 위한 작업을 한 적이 없고,

그럼 메모리 해제가 안된 건가???

 

그렇지 않다. 스위프트에서는 ARC를 통해 힙에 할당된 메모리를

자동으로 해제해 주기 때문이다.

(ARC(Automatic Reference Counting)는 이후의 글에서 다뤄보겠다!)

 

 

이 영역의 장점과 단점을 간단하게 알아보자면

 

장점으로는

메모리 크기에 대한 제한이 없고

- 프로그램의 모든 함수에서 액세스 할 수 있다는 것이다.
(본질적인 범위가 전역이기 때문이다.)

 

단점으로는

- 할당 작업, 해제 작업으로 인해 속도 저하

- 힙 손상 작업으로 인한 속도 저하

- 힙 경합으로 인한 속도 저하

메모리 누수(직접 관리가 필요)

 

 

 

 

 

스택(Stack) 영역

 

함수 호출 시 함수의 지역변수, 매개변수, 리턴 값 등이 스택 영역에 저장되고

함수가 종료되면 저장된 메모리도 해제된다.

 

컴파일 타임에 결정되기 때문에 무한히 할당할 수 없다.

 

 

func add(_ a: Int, _ b: Int) -> Int { //파라미터 a, b는 스택에 할당
    let result = a + b				  //지역변수 result 역시 스택에 할당
    return result					  
}

 

만일 위와 같은 함수를 호출하면

OS 내부적으로 함수 안에 선언된 파라미터, 지역변수 등을 스택 영역에 할당된다.

 

그리고 설명대로 함수가 종료되는 시점에 메모리 역시 해제된다.

 

스택의 특징은 LIFO(last in, first out)이다. (자료구조를 공부해 봤다면 아는 기본 구조)

또 CPU에 의해 관리되고 최적화 돼서 속도가 매우 매우 빠르다고 한다.

 

그럼 스택의 장, 단점은 무엇일까?

 

장점

- CPU가 스택 메모리를 효율적으로 구성하기에 속도가 매우 빠름

- 메모리를 직접 해제하지 않아도 됨

스레드 별로 독립적인 stack 영역을 가지고 있어 thread-safetythread-safety 하다.

 

단점

메모리 크기에 대한 제한

- 지역 변수만 액세스 가능

 

 

 

어? 장, 단점을 보니

힙과 스택이 서로 대비되는 것으로 보이는데,

힙과 스택의 자세한 부분은 다음글에서 다뤄보겠다.