-
안녕하세요. 그린입니다!
이번 포스팅에서는 ARC에 대해 심화적으로 알아보겠습니다.
- ARC란?
: Automatic Reference Counting (자동참조계수)를 뜻한다.
: 다른 언어에는 없는 독창적인 것으로 자바의 가비지 컬렉션 기법과는 다름 (메모리 해제 시점에 관한 이해가 필요) - 자동참조계수란?
: 앱의 메모리 사용을 추적하고 관리해준다.
: 인스턴스가 더이상 필요하지 않을때 클래스 인스턴스에 사용된 메모리를 자동으로 해제해준다. (참조 타입의 할당 / 해제 시점을 자동 관리)
: 클래스의 인스턴스(참조 타입)에만 적용 (구조체/열거형 등 값 타입에는 적용되지 않는다) - ARC 특징
1) 하나의 활성화 참조가 있다면 인스턴스는 할당 해제되지 않고 계속 존재
2) 강한참조의 할당을 nil로 정리해준다면 할당 해제된다.
3) 객체 생성 및 공유 시 마다 카운터(참조횟수)를 업데이트 해준다. - ARC 사용
=
: 이 부분에서 참조된 2개에 강한참조로 인스턴스가 메모리에 할당된다.
-> 만약 1/2를 nil로 할당하면 강한 참조는 깨지고 마지막 3의 강한참조만 남고 Person 인스턴스는 할당 해제되지 않는다.
: 마지막 남은 강한 참조를 nil로 깨주면 Person 인스턴스가 할당 해제된다.
- ARC의 여러 참조 종류
1) 강한참조
: 프로퍼티, 변수, 상수에 대해 기본값으로 설정되어 있는 참조 옵션
: 참조횟수가 0일시 해제되고 디이니셜라이저가 호출됨 (자동)
: 여러개의 인스턴스가 서로 참조할 시 강한 참조 순환 문제 발생 가능성 농후
: 메모리 해제 시점 이해없이 사용 시 인스턴스가 영원히 메모리에서 해제되지 않는 메모리 누수가 일어남
(약한참조 / 미소유참조로 해결 가능)
2) 약한참조
: weak 옵션 키워드를 붙여 생성
: 자신이 참조하는 인스턴스의 참조횟수를 증가시키지 않음
: 항상 옵셔널로 사용
3) 미소유참조
: unowned 옵션 키워드 붙여 생성
: 참조하는 인스턴스가 항상 메모리에 존재할거라는 기반을 가지고 사용 - 강력참조순환
: 클래스 인스턴스 사이의 강력참조순환의 문제가 발생할 수 있다.
: 두 클래스 인스턴스가 서로 강력 참조를 하고 있을때 각 인스턴스의 참조를 깨줘도 계속 살아 유지되어 메모리 누수를 야기하게되는것
: 서로 클래스가 참조하고 있다.
: 이럴 시 해당 두 클래스 인스턴스는 서로 강력참조순환을 한다. (아래 그림과 같은 형태이다): 해당 인스턴스들의 할당을 깨줘도 서로 강력참조순환은 남아있다.
- 강력참조순환 해결방안
-> 약한참조와 미소유 참조가 있다. 참조 순환 안에 있는 인스턴스가 다른 인스턴스에 강한 참조를 유지할 필요없이 참조
(즉, 각각 강력 참조 순환을 만들지 않고 서로 참조 할 수 있음)
1) 약한참조
: 객체가 옵셔널이라 해당 객체가 해제되었는데 참조하게되면 앱이 강제종료된다. (언래핑을 통해 안전하게 사용 필요)
: weak를 붙여 약한 참조
: 강력 순환 참조가 깨짐
: 강한 참조를 깨서 남아있지 않게됨
: 이후 number73 = nil로 주면 디이니셜라이저가 할당 해제됨을 알린다. (강한 순환 참조가 깨진 증거)
2) 미소유 참조
: 약한 참조와 비슷하지만 항상 값이 있음을 가정한다. (옵셔널이 아닌 타입으로 정의됨): 옵셔널이 아님으로 사용 시 언래핑할 필요가 없음 (항상 직접 접근이 가능)
: 인스턴스 할당 해제 시 참조를 nil로 설정할 수 없음 (옵셔널이 아닌 타입 변수는 nil로 설정될 수 없기에)
: 절대 nil일 수 없다!!! (옵셔널 객체가 아니다) -> 매우 위험한 방법으로 대부분 weak 사용: 이후 할당 해제되면 해제된다 (강력 참조 순환이 없기에)
- 클로저의 강한 참조 순환 -> 문제 발생 시 획득목록을 통해 해결 (강한획득, 약한획득, 미소유획득)
-> Capture list: 대괄호로 넣어 표현하며 외부에서 발생하는 변화에 반응하지 않음 - ARC 이전 메모리 관리는 어떻게?
: MRC(Manual Reference Counting), MRR등 개발자가 수동으로 직접 메모리 관리
-> alloc, new, copy, mutableCopy, retain 등을 사용하여 레퍼런스 증가
-> release를 사용하여 레퍼런스 감소 - 레퍼런스 카운팅을 하는 이유?
: 참조의 시점을 알기 위해서 - 애플리케이션이 빌드되는 단계
1) Compile (ARC가 이뤄지는 단계)
2) Linking
3) Runtime (가비지 컬렉션, GC는 이 단계에서 동적으로 감시하다가 필요 없을 시 해제됨) - weak unowned 차이
1) 사용되는 시점
: unowned는 다른 인스턴스의 생명주기 같거나 더 긴 경우
: weak는 다른 인스턴스의 생명주기 짧은 경우
2) 객체가 사라지면 nil로 바뀌는 weak에 반면 unowned는 객체가 사라지면 댕글로 포인터가 남음
: 댕글러포인터? 원래 바라보던 객체가 해제되면서 할당되지 않는 공간을 바라보는 포인터
[참고자료]
http://minsone.github.io/mac/ios/swift-automatic-reference-counting-summary
https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html
https://shark-sea.kr/entry/iOS-ARC-strong-weak-unowned
야곰의 스위프트 프로그래밍(3판)
'Swift' 카테고리의 다른 글
lazy var (0) 2021.03.17 Swift Performance (0) 2021.03.01 Type Casting (0) 2021.01.29 Protocol Oriented Programming (0) 2021.01.28 타입 메서드 (0) 2021.01.27 - ARC란?