[Swift] ARC (Automatic Reference Counting)

2023. 2. 28. 16:16🍏/OS

컴파일 시 자동으로 구문 분석 후 적절하게 레퍼런스 감소 코드를 삽입
메모리상의 변수, 상수, 객체 등을 자동으로 관리.

참조 카운팅이 0이 될 때, 메모리에서 해제.

 

요약

  • Running state 중 별도의 메모리 관리가 이루어지지 않는다.
  • 참조 카운팅은 클래스 타입의 인스턴스에만 적용되고 값 타입인 구조체 열거형 등에는 적용되지 않는다.
    - 값 타입은 정적 메모리 공간에 생기는 것이라서 메모리 관리 대상이 아님.
  • ARC는 더 이상 필요하지 않은 클래스의 인스턴스를 메모리에서 해제하는 방식으로 동작.

장점

  • 컴파일 시 인스턴스 해제 시점이 정해져 있어서 인스턴스가 언제 메모리에서 해제될지 예측 가능.
  • 위와 같은 이유로 메모리 관리를 위한 시스템 자원을 추가할 필요가 없음.

단점

  • 작동 규칙을 모르고 사용하면 강한순환참조가 일어나 인스턴스가 메모리에서 해제되지 않을 가능성이 있다.

ARC의 작동 방식  How ARC Works

 

클래스의 새 인스턴스를 생성할 때마다 ARC는 해당 인스턴스에 대한 정보를 저장하기 위해 메모리 청크를 할당.
이 메모리에는 인스턴스 유형에 대한 정보와 해당 인스턴스와 관련된 저장된 프로퍼티의 값이 포함.


인스턴스가 더 이상 필요하지 않은 경우 ARC는 해당 인스턴스가 사용하던 메모리를 해제하여 다른 용도로 메모리를 사용할 수 있도록 한다. 이를 통해 클래스 인스턴스가 더 이상 필요하지 않을 때 메모리 공간을 할당 해제.

그러나 ARC가 아직 사용 중인 인스턴스를 할당 해제하면 더 이상 해당 인스턴스의 프로퍼티에 액세스 하거나 해당 인스턴스의 메서드를 호출할 수 없게 된다. 실제로 인스턴스에 액세스 하려고 하면 앱이 충돌할 가능성이 높습니다.

인스턴스가 여전히 필요할 때 사라지지 않도록 ARC는 현재 각 클래스 인스턴스를 참조하는 프로퍼티, 상수 및 변수의 수를 추적. ARC는 해당 인스턴스에 대한 활성 참조가 하나 이상 남아 있는 한 인스턴스를 할당 해제하지 않는다.

이를 가능하게 하기 위해 클래스 인스턴스를 속성, 상수 또는 변수에 할당할 때마다 해당 속성, 상수 또는 변수는 인스턴스에 대한 강력한 참조를 생성. 이 참조를 "Strong" 참조라고 부르는 이유는 이 참조가 해당 인스턴스를 확고하게 유지하며, 강력한 참조가 남아 있는 한 인스턴스를 할당 해제할 수 없기 때문.


 

클래스간의 강한 순환참조 Strong Reference Cycles Between Class Instances

 

strong reference cycles
Memory not freed due to "strong reference cycles"

두클래스를 사용할 수 없음에도 불구하고, 두 클래스 인스턴스가 서로에 대한 강한 참조를 갖고 있어서, 메모리에서 해제가 되지 않는다. (Memory Leak)


강한순환참조 해결방법 Resolving Strong Reference Cycles Between Class Instances

  • 약한 참조 (weak reference)
    - 다른 인스턴스의 수명이 더 짧을 때 사용한다. (다른 인스턴스의 할당이 먼저 해제되는 경우)
  • 무소속 참조 (unowned reference)

약한 참조와 무소속 참조는 참조 순환에 있는 인스턴스 하나가 다른 인스턴스를 강하게 쥐고 있지 않아도 참조하도록 해준다. 이 인스턴스들은 강한 참조 순환을 생성하지 않아도 서로를 참조할 수 있다.

Weak References (약한 참조)

  • 참조하는 인스턴스를 강하게 쥐지 않는 참조 - ARC가 참조된 인스턴스를 처분하는 것을 중지하지 않음
  • ARC가 약한 참조를 nil로 설정할 때는 property observers가 호출되지 않음.

Unowned References (무소속 참조)

  • 다른 인스턴스가 같은 수명 또는 더 긴 수명을 가지고 있을 때 사용
  • 항상 값을 가지고 있어야 하며, 옵셔널이 될 수 없고, ARC는 절대로 무소속 참조의 값을 nil로 설정할 수 없음.
  • 무소속 참조는 해당 참조가 해제되지 않는 인스턴스만 항상 참조한다고 확신할 수 있을 때만 사용 해당 인스턴스가 해제된 후에는 무소속 참조의 값에 접근하려고 하면, 런타임 에러가 발생.