ARC - 메모리 관리

2025. 9. 28. 20:46·Swift

iOS 개발에서 메모리 관리는 앱의 안정성과 성능을 결정짓는 핵심 요소이다. Swift는 ARC라는 자동 메모리 관리 방식을 제공하여 개발자가 직접 메모리 할당과 해제를 수행하지 않도록 돕고 있다.

하지만 ARC가 자동으로 관리해 준다고 해서 동작 원리를 이해하지 못한다면 Memory Leak, Retain Cycle 같은 문제가 생긴다. 

ARC의 기본 개념부터 내부 동작 방식을 알아보자.

 


1. ARC란?

ARC(Automatic Reference Counting)는 Swift의 자동 메모리 관리 시스템으로 컴파일 시점에 객체의 생명주기를 추적하여 사용이 종료된 인스턴스를 메모리에서 해제한다. 핵심 동작은 객체가 참조될 때 Reference Count를 1 증가시키고, 참조가 해제될 때 Reference Count를 1 감소시킨다. 그렇게 Reference Count가 0이 되면 ARC가 객체를 메모리에서 제거하게 된다.

예시 코드와 함께 보자.

 

2. 메모리 관리 흐름

class Person {
    let name: String
    init(name: String) { 
        self.name = name 
        print("\(name) is initialized")
    }
    deinit {
        print("\(name) is deinitialized")
    }
}

var a: Person? = Person(name: "John")

Swift에서 class 타입의 인스턴스를 생성하면 ARC가 즉시 RC(Reference Count)를 1로 설정한다.

Person(name: "John") 코드 실행 시 Heap 영역에 새로운 Person 인스턴스가 생성된다. a라는 변수가 이 인스턴스를 참조하기 때문에 RC = 1이다. ARC는 생성 직후부터 이 인스턴스의 참조 수를 추적하기 시작한다.

 

class Container {
    var item: Person?
}

var b = Container()
b.item = a

새로운 클래스 Container를 만들고, 변수 b가 Container 인스턴스를 참조해서 Container 인스턴스도 RC가 1이 된다.

 

b.item = a 를 실행 시 Container가 Person을 참조하게 된다. 그럼 Person 인스턴스를 a와 b.item 두 곳에서 참조하기 때문에 RC = 2가 된다.

 

 

이제 메모리 해제 과정이다.

ARC는 Reference Count가 0이 되는 순간 객체를 메모리에서 해제한다.

a = nil

a가 Person에 대한 참조를 해제하므로 Person RC가 2 → 1 감소한다.

여전히 b.item이 Person을 참조하고 있으므로 Person은 해제되지 않는다.

 

b가 Container에 대한 참조를 해제하므로 Container RC가 1 → 0 감소한다. ARC가 Container를 메모리에서 해제한다. Container가 해제되면서 내부 프로퍼티 item도 함께 해제 → Person의 RC가 1 → 0 감소한다. Person의 RC가 0이 되었으므로 ARC가 Person도 메모리에서 해제한다.

이렇게 참조가 0이 되는 순간 ARC는 힙 메모리를 해제하게 된다.

 

3. 순환 참조(Retain Cycle) 문제

이렇게 ARC의 메모리 관리가 이루어지는데 이 과정에서 어떤 문제가 생기는 걸까?

순환 참조라는 것은 서로가 서로를 참조했을 때 참조 카운트가 0이 되지 않아서 ARC가 인스턴스를 해제하지 못하고 메모리 누수가 발생하게 되는 것을 말한다. 아래 코드를 보자

class Person {
    var apartment: Apartment?
    deinit { print("Person deinit") }
}

class Apartment {
    var tenant: Person?
    deinit { print("Apartment deinit") }
}

var john: Person? = Person()
var apt: Apartment? = Apartment()

john?.apartment = apt
apt?.tenant = john

john = nil
apt = nil
//  → 메모리 누수 발생

var john: Person? = Person()

var apt: Apartment? = Apartment() 이 두 코드로 각각의 인스턴스의 RC가 1씩 증가.

john?.apartment = apt

apt?.tenant = john 이 두 코드로 각각의 인스턴스끼리 참조하여 RC가 2가 된다.

 

john = nil
apt = nil

이제 두 변수를 모두 nil로 주게 되면 john과 apt는 참조가 제거되었지만, Heap 내부에서 여전히 서로 참조가 남아있다. 서로가 서로를 붙잡고 있어서 RC가 절대 0이 되지 않게 된다.  ARC는 RC가 0이 되어야 메모리를 해제하기 때문에 두 객체가 메모리 누수(Memory Leak) 상태가 된다! 사용되는 곳은 없는데 힙메모리에서 계속 자리만 차지하고 있으니 낭비가 되게 된다. 그러면 이 문제를 어떻게 해결할 수 있을까?

 

4. Strong / Weak / Unowned 참조

Swift에서 객체 간의 관계를 표현할 때, 참조의 강도에 따라 strong, weak, unowned 세 가지로 나뉜다. 기본적으로 참조 종류를 명시하지 않으면 strong(강한) 참조를 하게 된다. 우리는 지금까지 강한 참조를 해왔다. 변수가 객체를 참조하는 순간 RC가 증가하고 이 참조가 해제되어야 RC가 감소한다.

 

Weak(약한) 참조

weak 키워드는 참조를 약하게 만든다. 그래서 RC가 증가하지 않으며 참조가 해제되면 자동으로 nil이 할당된다. 이 nil 때문에 weak 변수는 Optional 타입이어야 한다.

class Person {
    let name: String
    init(name: String) { self.name = name }
    deinit { print("\(name) is deinitialized") }
}

class Apartment {
    weak var tenant: Person?
}

var john: Person? = Person(name: "John")
var apt: Apartment? = Apartment()

apt?.tenant = john
john = nil // John 해제 → tenant는 자동으로 nil

 

 

Unowned(미소유) 참조

unowned 키워드는 weak과 비슷한데 Optional이 아니고 참조 대상이 사라졌을 때 nil을 할당하지 않는다. 만약에 이미 해제된 객체에 접근하려고 하면 런타임 에러가 발생한다. 그럼 unowned를 언제 사용하느냐. 참조 대상이 절대 먼저 해제되지 않음을 보장할 수 있을 때 사용한다. 

class CreditCard {
    unowned let owner: Person
    init(owner: Person) {
        self.owner = owner
    }
}

class Person {
    var card: CreditCard?
}

var john: Person? = Person()
john?.card = CreditCard(owner: john!)

john = nil 
// 이제 CreditCard의 owner 접근 시 런타임 에러 발생

 

 

5. 정리

ARC는 Swift가 제공하는 자동 메모리 관리 시스템으로, 개발자가 직접 메모리 해제 코드를 작성할 필요는 없지만 동작 원리와 참조 타입을 이해하여 문제를 해결할 수 있도록 하자.

참조 타입 RC 증가 여부 Optional  타입 사용 상황
strong Reference Count 증가 X 기본값, 일반적인 참조
weak Reference Count 증가 X O (Optional) 순환 참조 방지, 참조 대상이 사라질 수 있는 경우
unowned Reference Count 증가 X X 참조 대상이 절대 먼저 사라지지 않는다고 확신할 수 있는 경우

 

'Swift' 카테고리의 다른 글

Any, AnyObject  (0) 2025.03.08
형변환  (0) 2025.03.08
옵셔널 (2)  (0) 2025.03.07
옵셔널 (1)  (0) 2025.03.06
[03] 1주차: 버튼과 텍스트를 사용하여 UI 실습  (1) 2025.03.05
'Swift' 카테고리의 다른 글
  • Any, AnyObject
  • 형변환
  • 옵셔널 (2)
  • 옵셔널 (1)
엽다고
엽다고
얼리지 않으면 상해버려
  • 티스토리 홈
  • 엽다고
    개발 냉장고
    엽다고
  • 글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기 (28)
      • iOS (0)
      • Swift (10)
      • Algorismus (9)
      • Godot (0)
      • C++ (3)
      • Python (4)
      • 디자인 (2)
        • HIG (1)
        • 디자인 시스템 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    암묵적인 언래핑
    EOF
    디자인시스템
    성능
    브루트포스
    문자열 보간
    논리 연산
    AnyObject
    HIG
    백준
    implicitly unwrapped
    옵셔널 바인딩
    이분탐색
    any
    강제 언래핑
    ARC
    C++
    Optional
    옵셔널
    SWIFT
    지마켓 디자인시스템
    타입검사
    앱개발
    swiftUI
    코테
    알고리즘
    모형화
    테이터 타입
    Swift 문법
    코딩테스트
  • hELLO· Designed By정상우.v4.10.3
엽다고
ARC - 메모리 관리
상단으로

티스토리툴바