[iOS / Swift] 메모리 기초

2025. 2. 28. 21:06

우선 ARC를 공부하기 전에 메모리 구조를 알아야함. 처음 공부하는건데 와. 신난다. 후...

1. 메모리 구조

먼저 프로그램이 실행이 되면 OS는 메모리(RAM)에 이 프로그램을 위한 공간을 할당

그 공간은 코드, 데이터, 힙, 스택으로 나누어서 사용

소들이 메모리 구조에서 발췌



1-1 코드 영역

우리가 작성한 소스 코드가 기계어 형태로 저장됨 (기계어 : 0과 1)

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

 

즉,

  • 코드 자체가 올라가는 영역
  • 앱의 기계어 코드(컴파일 결과물), 상수 문자열 같은 것들이 이곳에 저장됨
  • 수정이 불가능한 읽기 전용 메모리

1-2 데이터 영역

전역변수, static 변수가 저장

프로그램의 시작과 동시에 할당되고, 프로그램이 종료되어야 메모리가 해제

실행 중에 변수 값이 변경될 수 있으니 Read-Write로 지정

import UIKit

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

var name: String?                   // 전역 변수로 데이터 영역에 할당
var age: Int?                       // 전역 변수로 데이터 영역에 할당
func fetchDate() {
    
}

위 코드를 보면 name과 age는 전역 변수로, country는 static 상수로 데이터 영역에 할당이 됨.

 

근데, 일반적인 프로그래밍이아닌 Swift에서 static은 기본 동작이 `lazy`임.

즉, 프로그램이 시작할 때 무조건 데이터 영역에 올라가는 것이 아니라, 정말 필요할 때(처음 접근시) 생성되고 메모리에 올라가는 구조임.

나머지는 똑같이 한 번 초기화되면 프로그램이 끝날 때까지 메모리에 유지됨!

변수 데이터 영역 저장 여부 비고
`Korean.Country` 데이터 영역 (static let) 프로그램 시작~끝까지 유지
`name` 데이터 영역 (전역 변수) 프로그램 시작 시 nil로 초기화
`age` 데이터 영역 (전역 변수) 프로그램 시작 시 nil로 초기화

 

 

  • `Korean.country`는 `struct` 안에 있지만, static 변수라서 인스턴스 생성과 상관없이 바로 데이터 영역에 올라감.
  • `name`과 `age`는 글로벌 변수니까 데이터 영역에 저장됨.
  • `Swift`에서는 전역 변수도 옵셔널이면 기본적으로 `nil`로 초기화됨.

그러면 위에 설명에서 static변수는 인스턴스 생성과 상관없이 바로 데이터 영역에 올라간다 vs 정말 필요할 때 생성되고 메모리에 올라가는 구조 말이 안맞지 않음?

 

여기서 정말 나도 헷갈렸음.

설명을 하자면,

  • Swift의 `static`변수는 타입에 귀속되는 변수라서, 인스턴스 생성과는 상관없이 관리되는건 맞음
  • 하지만, 메모리에 올라가는 시점은 처음 접근할 때(lazy)임
  • 즉, 프로그램 시작과 동시에 데이터 영역에 올라가는건 아님.
  • 처음 접근하는 순간(lazy) 메모리를 먹기 시작 = 메모리에 올라감(lazy 초기화)

이렇게 이해했음. 틀렸으면 댓글로 알려주셈..ㅎ

 

 

추가로! 여기서 혹시 전역변수와 static 변수의 차이를 모르는 사람이 있을까봐 차이를 간단하게 적자면! 아래처럼 될거임

구분 전역 변수 static 변수
선언 위치 타입 밖 (파일의 최상단 등) 타입 안 (struct, class 등 내부)
접근 방법 바로 접근 `타입이름.변수이름`으로 접근
메모리 위치 데이터 영역 데이터 영역
수명 프로그램 전체 수명 프로그램 전체 수명
인스턴스 종속성 없음 없음(타입 자체에 귀속)
대표 예시 `var globalCount = 0` `struct Korean {
    static let country = "Korea" 
}`

 

1-3 힙 영역

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

프로그래머는 malloc, calloc으로 힙에 메모리를 할당할 수 있으며, 이를 동적 할당이라고 함

사용하고 난 후에는 반드시 메모리 해제를 해줘야함 그렇지 않으면 memory leak이 발생

코드, 데이터, 스택 중 유일하게 런타임 시에 결정되기 떄문에 데이터의 크기가 확실하지 않을 때 사용함.

 

단, Swift에서는 ARC를 통해 힙에 할당된 메모리가 더이상 쓸모가 없어지면(참조되지 않으면) 자동으로 해제를 해줌
(솔직히 ARC를 공부하기 전이기 때문에 일단 넘어가보겠음..)

 

그래서 Swift가 아닌 다른 언어에서는 반드시 메모리 해제를 해줘야함. 그에 따라 힙의 장단점도 알아보겠음

장점 메모리 크기에 대한 제한이 없음

본질적인 범위가 전역이기 때문에, 프로그램의 모든 함수에서 액세스 할 수 있음
단점 할당작업, 해제 작업으로 인한 속도 저하

힙 손상(이중 해제, 해제 후 사용 등) 작업으로 인한 속도 저하

힙 경합(두 개 이상 쓰레드가 동시에 접근하려 할 때 Lock)으로 인한 속도 저하

메모리를 직접 관리해야 함(해제하지 않을 시 메모리 누수 발생)

 

1-4 스택 영역

함수 호출 시 함수의 지역변수, 매개변수, 리턴 값 등등이 저장되고, 함수가 종료되면 저장된 메모리도 해제됨.

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

 

스택은 프로그램이 자동으로 사용하는 임시 메모리 영역임.

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

 

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

 

그리고 위 `add`함수가 종료되는 시점에 스택에 저장된 메모리는 알아서 반환됨.

 

또한 스택은 우리가 자료구조에서 배운 LIFO(Last in, First out)데이터 구조이기 때문에, CPU에 의해 관리되고 최적화 되기때문에 속도가 매우 빠름.

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

메모리를 직접 해제를 해주지 않아도 됨
단점 메모리 크기에 대한 제한이 있음

지역 변수만 액세스 가능

p.s) 지역변수란?

함수, 메서드, 또는 특정 블록(조건문, 반복문) 안에서 선언된 변수임.

해당 함수 / 블록이 실행될 때 생성되고, 그 함수 / 블록 이 끝나면 자동으로 사라지는 변수임


2. 힙 vs 스택

 

2-1. 언제 힙을 쓰고, 언제 스택을 쓸까?

 

스택을 쓰는 경우

대상 설명
지역 변수 함수, 메서드 안에서 선언되는 변수
매개변수 함수에 전달되는 값(기본적으로 값 타입인 경우)
값 타입(struct, enum) 함수 안에서 생성되는 struct, enum 등
클로저 캡처 외부 변수(일부 경우) 클로저가 캡처하지 않는 단순 지역 변수들은 스택에 유지

 

특징

  • 함수 호출 시 스택 프레임에 저장
  • 함수가 끝나면 자동 해제 (메모리 해제 걱정 없음)
  • 메모리 할당/해제가 매우 빠름
  • 크기가 상대적으로 작아야함 (큰 데이터는 힙으로 갈 수도 있기 때문)

힙을 쓰는 경우

대상 설명
클래스 인스턴스 클래스 객체는 무조건 힙에 저장
클로저 캡쳐한 변수 클로저가 외부 변수를 캡처하면, 힙에 저장될 수도 있음
큰 구조체(경우에 따라) 아주 큰 `struct`는 최적화를 위해 힙으로 갈 수도 있음 (일반적이진 않음)

 

특징

  • 메모리 할당/해제가 비교적 느림 (ARC 관리 필요)
  • 수명이 함수 범위를 넘어설 수 있음
  • 참조 카운팅(ARC)으로 관리됨 (retain/release)

그러면 만약에 스택에 크기가 큰 데이터 즉, 너무 많은 메모리를 할당하게 되면 스택 오버 플로우가 발생

 

스택 오버 플로우란?

스택에 너무 많은 메모리를 할당하게 되어 자신의 스택 영역을 초과한 경우를 말함.

iOS에서 스택 오버 플로우가 발생할 시 어플이 죽어버림

 

2-2 힙과 스택의 메모리 관계

힙과 스택은 같은 메모리 영역을 공유함.

 

같은 메모리 공간이지만, 힙은 낮은 메모리 주소부터 할당을 받고, 스택은 높은 메모리 주소부터 할당 받는 것임.

 

 

아 힘들다.. 소들이님 글 잘쓰시는데 내 머리가 이해를 못하는중..

 

 

참고: 소들이님 블로그 https://babbab2.tistory.com/25

 

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

안녕하세여~~ 소들입니다 :-))))) 오늘 웬 듣보잡 버그 한 놈이 나왔는데 처음에 메모리 참조 오류인 줄 알고 하루 종일 메모리에 대해서 공부 했는데 버그 원인은 메모리가 아니었음ㅋ (디코딩 네

babbab2.tistory.com