iOS - 메모리구조 (Code, Data, Stack, Heap)

이한솔·2023년 8월 24일
0

iOS 앱개발 🍏

목록 보기
12/49

메모리 구조

프로그램이 실행되면 운영체제(OS)는 메모리(RAM)에 프로그램을 위한 공간을 할당한다.
그 공간은 총 4가지 Code, Data, Heap, Stack으로 나뉘어져 있다.



Code

작성한 소스 코드가 기계어 형태(0,1로 구성)로 저장된다.
CPU가 여기에 저장된 명령어를 하나씩 가져가 처리한다.
중간에 코드가 변경되지 않도록 Read-Only 형태로 저장된다.



Data

전역변수, static변수가 저장된다.
프로그램 시작과 동시에 할당되고 프로그램이 종료되어야 메모리가 해제된다.
실행 도중 값이 변경될 수 있어서 Read-Write 형태로 지정된다.



Heap

클래스 인스턴스, 클로저 같은 참조 타입의 값이 힙에 할당된다.
Code, Data, Stack 중에 유일하게 런타임 시 크기가 결정된다.
사용하고 난 후에 반드시 메모리 해제를 해줘야하는데, ARC를 통해 힙에 할당된 메모리가 더 이상 참조되지 않으면 자동으로 해제된다.
(📌 ARC는 더 자세히 알아보도록 하자!)

장점

  1. 메모리 크기에 대한 제한이 없다.
  2. 본질적인 범위가 전역이기 때문에, 프로그램의 모든 함수에서 액세스 할 수 있다.

단점

  1. 할당작업, 해제 작업으로 인한 속도 저하
  2. 힙 손상 (이중 해제, 해제 후 사용 등) 작업으로 인한 속도 저하
  3. 힙 경합 (두 개 이상 쓰레드가 동시에 접근하려 할 때 Lock이 걸림)으로 인한 속도 저하
  4. 메모리를 직접 관리해야 함, 해제해주지 않을 시 메모리 누수가 발생한다.


Stack

지역변수, 함수 호출 시 함수의 매개변수, 리턴 값 등이 저장되고 함수가 종료되면 저장된 메모리도 해제된다.
마지막에 생성된 변수가 가장 먼저 해제되는 LIFO(last in, first out) 데이터 구조이고 CPU에 의해 관리되고 최적화되어서 속도가 빠르다.

장점

  1. CPU가 스택 메모리를 효율적으로 구성하기 때문에 속도가 매우 빠르다.
  2. 메모리를 직접 해제 해주지 않아도 된다.

단점

  1. 메모리 크기에 대한 제한이 있다.
  2. 지역 변수만 액세스 가능하다.


코드 예시

// 전역변수, Data 영역에 저장됨
var a: Int = 10
var b: String = "hs"


struct data {
    static let data = "data" // 타입변수, Data 영역에 저장됨
}


class Person {
    var name: String?
}

let person = Person()
// person 변수는 Stack에 저장됨
// Person() 인스턴스는 Heap에 저장됨


func main(){
    var person = Person()
}
// person 변수는 Stack에 저장됨
// Person() 인스턴스는 Heap에 저장됨


func add(a: Int, b: Int) -> Int {
    let result = a + b
    return result 
}
// 매개변수 a, b, 지역변수 result 다 Stack에 저장됨


💡 Heap & Stack

1. 언제 Heap을 쓰고, 언제 Stack을 쓸까?

Stack은 메모리가 한정되어 있기 때문에 너무 큰 메모리는 할당할 수 없다.
데이터의 크기를 모르거나, Stack에 저장하기엔 큰 데이터의 경우엔 Heap에 할당 하고 그 외엔 Stack에 할당하면 된다. (인스턴스, 클로저 등 자동으로 힙에 할당되는 것 외에 직접 할당할 경우) 만약 Stack에 너무 많은 메모리를 할당하게 되면 Stack over flow가 발생한다.

💡 Stack over flow?
스택에 너무 많은 메모리를 할당하게 되어 자신의 스택 영역을 초과한 경우,
iOS에서 Stack over flow 발생 시 앱이 crash된다.

2. 클래스 인스턴스 생성시

변수는 Stack에 저장되고, 그 변수는 Heap의 주소 값을 갖는다.
클래스 인스턴스를 Heap에 저장하려면 어디에 저장할지 찾아야 하고 멀티 스레드 환경에서 Locking, 해제과정 등 시간이 소요되기 때문에 클래스를 사용하는것은 Stack에 저장되는 구조체를 사용하는 것보다 오래 걸린다.
클래스와 구조체 두개 다 사용 가능한 경우, 구조체를 사용하는것을 권장하고 상속이나 참조와 같은 클래스만의 기능을 사용해야 할 경우 클래스를 이용한다.

3. 힙과 스택의 메모리 관계

힙과 스택은 같은 메모리 영역을 공유한다.
같은 메모리 공간에서 힙 영역은 낮은 메모리 주소부터 할당받고,
스택 영역은 높은 메모리 주소부터 할당 받는 것이다.
따라서 힙 또한 자신의 영역 외로 확장하려다 보면 Heap over flow가 발생한다.

0개의 댓글