Swift ARC 의 기본적인 개념은 아래 포스팅을 참고해주시면 감사하겠습니다.
필자는 iOS 를 처음 공부하며 클로저 캡처리스트를 작성할 때 unowned 를 남발했던 기억이 있습니다.
그 후 앱 크래시를 유발할 수 있다는 조언을 듣고 강한 순환 참조가 발생할 수 있는 상황에서는 weak 키워드를 사용했습니다.
weak 와 unowned 를 사용하면 레퍼런스 카운트가 올라가지 않고 self 가 옵셔널이라는 차이가 있다는
단편적인 이해를 하고 넘어갔었지만, 이번 포스팅에서는 조금 더 자세하게 ARC 동작에 대해서 다루겠습니다.
Swift Reference Count
Swift "RefCount.h" 헤더 파일의 주석을 참고하면 레퍼런스 카운트는 다음과 같이 3개로 나누어 집니다.
Strong RC
- 오브젝트를 참조할 때 기본적으로 사용되는 방식입니다.
- Strong 카운터 가 0이 되면 오브젝트가 deinited 됩니다. ( 메모리에서 해제를 의미하지는 않습니다. )
- String 카운터가 0일 때 unowned 레퍼런스를 읽으면 error, weak 레퍼런스는 nil 이 됩니다.
Unowned RC
- 오브젝트를 미소유(unonwned) 로 참조할 때 해당됩니다.
- 참조될 때 Unowned RC 카운트가 올라가고 해당 카운트는 오브젝트가 deinited 될 때 카운트가 내려갑니다.
- Unowned 카운터 가 0이 되면 오브젝트가 메모리에서 해제(free) 됩니다.
Weak RC
- 오브젝트를 약하게(weak) 참조할 때 해당됩니다.
- 참조될 때 Weak RC 카운트가 올라가고 해당 카운트는 오브젝트가 해제(free) 될 때 카운트가 내려갑니다.
- Weak 카운터 가 0이 되면, 해당 오브젝트의 Side Table 또한 해제됩니다.
* 코드 주석에 맞게 오브젝트로 용어를 통일하였습니다.
정리하자면 다음 그림과 같이 오브젝트 해제가 이루어집니다.
What is Side Table?
사이드 테이블은 Swift 4.0 버전부터 새롭게 도입된 기능입니다.
기존 방식은 Strong 과 Weak 두 가지의 참조 카운트를 가지고 있었습니다.
Strong 카운터가 0이 되면 deinit 되지만, 메모리에서 바로 free 되지는 않았습니다.
이처럼 메모리에 계속 남는 것을 좀비 오브젝트라고 불렀고, 그 후 weak 참조로 다시 접근하면
그제서야 메모리 해제가 이루어졌습니다.
이 방식은 매우 간단한 설계였지만 사용하지않는 오브젝트가 메모리에 계속 남는 것은 비효율적인 방식입니다. 따라서 Side Table 이라는 별도의 관리 개체를 만들게 되었습니다.
위 그림처럼 Strong 과 Unowned 는 오브젝트를 직접 가르키고, weak 는 side table 를 가르키게 됩니다.
해당 사이드 테이블은 다음과 같은 조건으로 생성됩니다.
1. Strong 혹은 Unowned 카운트가 오버플로우 될 때
2. Weak 참조를 사용할 때
이러한 side table 덕분에 Strong 카운트가 0가 되면 deinit 에서 메모리가 해제되는 과정을 거치게됩니다.
Weak vs Unowned?
Mike Ash 개발자에 따르면 side table 이 필요한 오브젝트는 추가 비용이 발생할 수 있다고 합니다.
* 구글링을 통해 weak unowned 키워드에 따른 유의미한 성능 차이는 찾지 못했습니다. 다만 별도의 오브젝트를 사용하므로
할당/해제에 발생하는 오버헤드가 있는 것은 분명한 사실입니다.
개발자가 오브젝트의 생명주기를 확실하게 파악한 상태이면 Unowned 키워드를 사용하고,
그 외의 경우라면 안전한 코딩을 위해 weak 키워드를 사용하는 것이 좋겠다는 생각이 들었습니다.
* unowned 키워드는 RxSwift, Alamofire 같은 유명한 라이브러리에서도 사용된
코드를 발견할 수 있었습니다. 상황에 따라 적절하게 사용가능할 것으로 보입니다.
참고:
'iOS Dev > Swift' 카테고리의 다른 글
iOS JSON 을 Decoding 하는 여러 가지 방식들 (0) | 2021.08.26 |
---|---|
지금까지 받았던 코드 리뷰 정리 ( iOS, Swift ) (0) | 2020.11.10 |
Swift Optional ( enum, wrapped ) 정리 (0) | 2020.10.12 |
Swift ARC ( Automatic Reference Counting ) 정리 (2) | 2020.10.07 |
윈도우 10 에서 Swift 5 사용하기 ( Visual Code, WSL ) (4) | 2020.08.01 |