본문 바로가기

iOS

[iOS] ARC and Strong, Weak, Unowned

RC


RC란, Reference Counting 의 약자로 애플에서 메모리를 관리하는 방법이다.

메모리를 할당하거나, 메모리 포인터를 참조할 때, 레퍼런스 카운트를 증가시키고 사용을 완료하면 레퍼런트 카운트가 감소된다.

이러한 메모리 관리 기법이 기존에는 manual하게, 개발자에 의해 수동으로 진행되었다.

이후 이를 자동으로 관리해주는 기능이 iOS 4부터 제공되기 시작했으며 이를 ARC(Automatic Reference Counting)이라고 한다.


ARC


참고로 애플리케이션은 Compile -> Linking -> Runtime 이렇게 3 단계를 거쳐서 빌드되고 만들어진다.

스위프트 공식 문서에 의하면 "Swift는 ARC를 사용하니 메모리 관리를 생각할 필요가 없다." 라고 한다.

하지만, 메모리 참조 순환에 대한 기본적 지식은 알고 사용하는 것이 바람직하다!

스위프트의 value type은 ARC 메모리 관리 대상이 아니다.

ARC의 주요 관리 대상은 클래스, 클로저 같은 reference type의 데이터다.

ARC는 클래스 인스턴스를 생성할 때, 메모리를 할당한다.

그리고 클래스 인스턴스가 더이상 필요하지 않을 때, ARC는 메모리를 해제한다.

순환 참조에 대한 기본 지식은 아래 3가지 키워드로 설명한다.

  • Strong
  • Weak
  • Unowned

각각 강한 순환 참조, 약한 순환 참조, 미소유 순환 참조 정도 라고 해석한다.

Strong

Swift에서 Strong은 어떠한 설정값도 없을 때 기본값이다.

즉, 별도의 지시자가 없을 때 기본적으로 이용하는 default 값이다.

Strong은 레퍼런스에 대한 강한 참조(Strong reference)를 유지하며 레퍼런스 카운트를 증가시킨다.

메모리를 동적으로 할당하거나 레퍼런스를 위한 포인터 등은 모두 힙(Heap) 영역에 할당된다.

따라서, Strong은 힙에 머무는것을 강제화 한다.

그런데 강한 순환 참조는 클로저 캡처링이나 객체간 상호 참조 등의 경우, RC가 0이 되지 않는 상황, 메모리 누수(Memory Leak)가 발생할 수 있다.

이러한 경우를 방지하기 위해 weak 약한 순환 참조와 unowned 미소유 순환 참족가 존재한다.

weakunowned는 모두 대상 객체에 대하여 레퍼런스 카운트(RC)를 변화시키지 않는다.

즉, 레퍼런스 카운트를 증가시키지 않는다는 것이다.

이 둘에 대해서 알아본다.


Weak

약한 순환 참조를 진행하는 경우에는 해당 객체가 nil일 수 있다.

따라서, 만일 weak 참조가 옵셔널인 경우에는 해당 객체가 메모리에서 사라진 상태에서 참조를 하게되어 Application이 강제 종료가 된다.

약한 참조를 참조할 때는 RC가 증가되지 않지만 인스턴스 참조가 가능하다. 만일 참조하고 있던 인스턴스가 메모리에서 해제되면 자동으로 nil이 할당되어 참조를 해제하고 메모리를 반환한다.

이러한 경우를 위해 weak는 언래핑 하는 과정을 통해 안전하게 사용할 수 있다.

약한 참조는 사용 이후 nil을 할당해야 하기 때문에 옵셔널 타입의 변수여야 한다.


Unowned

unowned는 해당 객체는 절대 nil일 수 없다. -> Optional 객체가 아니다! 를 의미한다.

미소유 참조 또한 약한 참조와 마찬가지로 RC를 증가시키지 않으면서 인스턴스를 참조한다.

하지만 미소유 참조는 인스턴스를 참조하는 도중 해당 인스턴스가 메모리에서 사라질 일이 없다고 가정한다.

일반적으로 약한 참조(weak)만 사용해도 문제가 없기 때문에, 특별한 경우가 아니라면 미소유 참조는 사용하지 않는 것이 좋다.


Summary


  • RC : Reference Counting, 메모리를 할당하거나 메모리 포인터를 참조할 때, 레퍼런스 카운트를 증가시키고 사용 완료시에는 레퍼런스 카운트가 감소된다.

  • value type은 메모리 관리 대상이 아니다, ARC 주요 관리 대상은 클래스, 클로저 같은 reference type의 데이터다.

  • Weak, Unowned 는 레퍼런스 카운트를 증가시키지 않는다.

  • Strong : Strong은 레퍼런스에 대한 강한 참조(Strong reference)를 유지하며 레퍼런스 카운트를 증가시킨다.

    • Strong 순환 참조는 메모리 할당을 힙에 강제화한다.
  • Weak : weak는 Optional로 힙에 어떠한 메모리를 가리키고는 있지만, 그 안에 들어있는 값이 사라졌을수도 있기 때문에 사라질 경우 그냥 nil로 설정하겠다는 것.

    • 약한 참조를 참조할 때는 RC가 증가되지 않지만 인스턴스 참조가 가능하다. 만일 참조하고 있던 인스턴스가 메모리에서 해제되면 자동으로 nil이 할당되어 참조를 해제하고 메모리를 반환한다.
  • unowned : 미소유 참조는 약한 참조와 마찬가지로 RC를 증가시키지 않으면서 인스턴스를 참조한다, 하지만 미소유 참조는 인스턴스를 참조하는 도중 해당 인스턴스가 메모리에서 사라질 일이 없다고 가정하기 때문에 약한참조와 달리 암묵적으로 강제 언래핑하여 선언한다.


Reference


'iOS' 카테고리의 다른 글

[iOS] SwiftUI 개요  (0) 2020.07.17
[iOS] TableView  (0) 2020.07.16
[iOS] Core Data  (0) 2020.07.11
[iOS] Storyboard vs Code-based UI & DispatchQueue  (0) 2020.07.05
[iOS] Codable and JSON Encoder & Decoder  (0) 2020.07.04