🔥 ARC는 어떻게 동작하는가?

345자
5분

Swift에서는 ARC(Automatic Reference Counting)라는 메모리 관리 기법을 사용하여 메모리를 효율적으로 관리합니다. 클래스의 인스턴스를 생성할 때마다 ARC는 해당 인스턴스에 대한 정보를 저장하기 위해 메모리 공간을 할당하지요. 이 메모리에는 인스턴스의 타입 정보와 함께 인스턴스와 연관된 저장 속성의 값들이 저장됩니다.

class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) is being initialized")
    }
    deinit {
        print("\(name) is being deinitialized")
    }
}
 
var reference1: Person?
var reference2: Person?
var reference3: Person?
 
reference1 = Person(name: "John Appleseed")
// "John Appleseed is being initialized" 출력
swift

위의 코드에서는 Person 클래스의 인스턴스를 생성하고 있습니다. reference1 변수에 Person 인스턴스를 할당하면, 해당 인스턴스를 위한 메모리가 할당되고 초기화 코드가 실행되면서 "John Appleseed is being initialized"라는 메시지가 출력되겠죠.

그런데 만약 인스턴스가 더 이상 필요하지 않게 되면 어떻게 될까요? ARC는 더 이상 필요하지 않은 인스턴스가 사용하던 메모리를 해제하여 다른 용도로 사용할 수 있도록 합니다. 이를 통해 더 이상 필요하지 않은 클래스 인스턴스들이 메모리 공간을 차지하지 않도록 하는 거죠.

하지만 만약 ARC가 아직 사용 중인 인스턴스를 할당 해제한다면 어떻게 될까요? 그 인스턴스의 속성에 접근하거나 메서드를 호출하는 것이 불가능해질 겁니다. 인스턴스에 접근하려고 하면 앱이 크래시 날 가능성이 높아질 거예요.

따라서 ARC는 각 클래스 인스턴스를 참조하고 있는 속성, 상수 및 변수의 수를 추적합니다. 그리고 해당 인스턴스를 가리키는 활성 참조(active reference)가 하나라도 존재하는 한 인스턴스를 할당 해제하지 않습니다.

이를 가능하게 하기 위해, 클래스 인스턴스를 속성, 상수 또는 변수에 할당할 때마다 해당 속성, 상수 또는 변수는 인스턴스에 대한 강한 참조(strong reference)를 만듭니다. 이 참조를 "강한" 참조라고 부르는 이유는 강한 참조가 존재하는 한 인스턴스를 확실하게 잡아두고 할당 해제되지 않도록 하기 때문이에요.

reference2 = reference1
reference3 = reference1
reference1 = nil
reference2 = nil
reference3 = nil
// "John Appleseed is being deinitialized" 출력
swift

위의 코드에서는 reference1이 참조하던 Person 인스턴스를 reference2reference3도 참조하도록 했습니다. 그 후 reference1, reference2, reference3을 모두 nil로 설정했죠.

nil로 설정하는 것은 해당 변수들이 더 이상 Person 인스턴스를 강하게 참조하지 않음을 의미합니다. 마지막 강한 참조마저 사라지면서 Person 인스턴스는 메모리에서 해제되고, deinit이 호출되면서 "John Appleseed is being deinitialized"라는 메시지가 출력됩니다.

이처럼 ARC는 클래스 인스턴스의 활성 참조 수를 추적하여 메모리를 적절히 관리합니다. 이를 통해 메모리 누수를 방지하고 앱의 안정성을 높일 수 있게 되는 것이죠.