[Swift] ARC

E_H·2021년 9월 24일
0

Swift

목록 보기
11/11

ARC란?

Swift의 메모리 관리 모델로 ARC를 통해 메모리 해제시점을 파악합니다.

reference Type은 힙 메모리 영역에 저장하기 때문에

스택영역과 다르게 관리를 해야합니다.

힙에 할당이 되고 해제하지 않으면 메모리 누수(Memory leak)이 발생되어

성능이 좋지 않아집니다.

Swift는 ARC(Automatic Reference Count)로 자동으로 RC를 세어줍니다.

논외로 Objective - C 는 MRC(수동관리), ARC
JAVA는 Garvage Collection으로 메모리를 관리합니다.

클래스 내부에는 reference Count를 세는 것이 있습니다.

클래스를 참조할 때마다 이 count가 1 올라가며

0이 되면 메모리에서 해제할 수 있습니다.

Memory leak

Swift ARC 문서에서 예시코드를 가져왔습니다.

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

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person? // 앞의 예제와 이 부분이 다르다!
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person?
var unit4A: Apartment?

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

persons 변수와 apartment변수는 각각 Person, Apartment 클래스를 참조하며 클래스들은 소멸시 print문을 실행합니다.

변수들이 클래스들을 참조할 경우 그림과 같은 모습이며
참조할경우 RC는 1 올라가지만
변수에 nil을 하면 RC는 0이 되어 소멸되어 deinit print문이 출력됩니다.

하지만 서로 참조를 할 경우 아래와 같은 모습이 되며

john!.apartment = unit4A
unit4A!.tenant = john

클래스를 참조한 변수에 nil을 할당하더라도 RC가 0이 아니기 때문에
소멸하지 않습니다.

john = nil
unit4A = nil

이 경우 강한참조 사이클이라 부르며
메모리 해제가 되지 않아 메모리 누수(Memory leak)이 발생됩니다.

강한 참조 사이클 방지

swift에서는 이 문제를 해결하기 위해
weak, unowned 키워드를 사용하여 해결합니다.

weak과 unowned는 nil을 통해 메모리에서 해제할 수 있어야 하기 때문에
optional 타입으로 사용합니다.

공통점으로 한 쪽의 인스턴스가 해제되면 참조하는 다른 쪽 인스턴스 또한 자동으로 해제가 됩니다.

예를 들어

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

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person? // weak 추가
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person?
var unit4A: Apartment?

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

앞의 예제 코드에서 weak 를 추가한 상태입니다.

이 경우 아래 그림과 같은 형태가 되며

john!.apartment = nil

persons에 nil을 할당하여 해제하면

Person을 참조하던 john은 해제되면서 Person클래스는 소멸되고

Person을 weak로 참조하던 unit4A 또한 해제되면서

강한 참조는 사라지게 됩니다.

unit4A = nil

여기서 unit4A 또한 nil을 주게 되면

Apartment를 참조하는 인스턴스 또한 해제되며 Apartment 클래스는 소멸되면서 deinit print문을 호출하게 됩니다.

unowned 키워드 또한 weak과 같은 기능을 하지만

차이점이라면 nil을 자동할당하지 않아 객체가 사라지면 댕글링 포인트가 남게 되는데

이때 사라진 객체에 접근하면 에러가 발생됩니다.

댕글링 포인터: 원래 바라보던 객체가 해제되면서 할당되지 않는 공간을 바라보는 포인터

참고

https://devsrkim.tistory.com/entry/Swift-메모리를-참조하는-방법-Strong-Weak-Unowned

https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html

0개의 댓글