[iOS] 메모리 참조 방법 (Strong, Weak, Unowned)

nnnyeong·2021년 11월 17일
0

iOS

목록 보기
7/17
post-thumbnail

(할때마다 오랜만이어서 민망한 iOS 포스팅,,ㅎ)

오늘은 메로리 참조 방식에 대해 공부 해 보았다. 크게 강한 참조, 약한 참조, 미소유 참조로 나뉘게 되는데 비록 본격적으로 사용해본 적은 없지만 몇번 면접에서 마주했던 내용이니 알아두자!




ARC (Auto Reference Counting)

먼저 ARC 에 대해 간단히 정리해보면

ARC, Auto Reference Counting 은 iOS 앱 내에서 발생하는 메모리 누수 현상을 자동으로 관리해주는 시스템이다.

컴파일시 코드를 분석해 자동으로 retain, release 코드를 생성하며 참조된 횟수를 추적해서 더 이상 참조되지 않는 인스턴스를 메모리에서 해제해 메모리가 낭비되지 않도록 한다.

또한 ARC 는 클래스 인스턴스에만 적용되는데 구조체나 열거형은 값 타입이기 때문에 참조에 의해 전달되거나 저장되지 않으므로 ARC 의 대상이 아니기 때문이다.

이때 ARC 의 관리 대상이 되는 클래스 인스턴스들의 참조 방식은 크게 강한 참조, 약한 참조, 미소유 참조 세가지로 나뉜다.




강한 참조 (Strong Reference)

가장 기본적인 참조 방식이고 특별히 지정하지 않으면 모두 강한 참조 방식ㅇㄹ 따른다.

강한 참조 방식 사용시 해당 인스턴스에 대한 소유권을 갖게 되고 참조하는 인스턴스의 reference count 를 1 증가시킨다. 값을 지정하는 시점에 retain 되고 nil 을 저장해 참조를 종료하는 시점에 release 된다.

다음과 같은 예시를 보자.

현재 johnunit4A 변수는 각각 Person, Apartment 인스턴스를 강하게 참조 하고 있다.





이때 각 인스턴스의 변수로 서로를 참조하도록 하면 강한 순환 참조 형태가 형성되고

각 참조 값을 해제하면 두 변수 name, tenant 가 참조하는 값들은 해제되지 못하고 메모리 상에 남아있게 되지만 john, unit4A 값을 해제했기 때문에 메모리 누수가 발생하게 된다.

nil로 강한 참조를 깼지만 순환 참조는 해결되지 않았고 john, unit4Anil로 설정되어도 두 클래스 인스턴스의 reference count 는 모두 0이 되지 못했기 때문에 소멸자가 호출되지 않고 메모리에서 해제되지 못하는 상황이 발생한다.



강한 순환 참조 문제 (Strong Reference Cycle)

ARC는 인스턴스 참조의 갯수를 추적할 수 있고 참조 변수가 더 이상 사용되지 않는 경우에는 알아서 메모리에서 해제한다.

하지만 두개의 클래스 인스턴스들이 서로를 붙잡고 있을때 클래스 인스턴스가 강한 참조 카운트가 0이 되는 시점을 절대로 알지 못할 수도 있다.




약한 참조 (Weak Reference)

이러한 강한 순환 참조에 의한 메모리 누수 문제를 해결하는 방법으로는 약한 참조가 있다.

약한 참조는 해당 인스턴스의 reference count 가 증가하지 않는다. 또한 약한 참조가 무언가를 참조하고 있는 중에도 인스턴스를 정상적으로 해제할 수 있는데 이는 인스턴스가 해제될 때 ARC에서는 해당 참조에 대해 자동으로 nil을 설정하기 때문이다.

약한 참조는 런타임중에 nil 로 변경될 수 있어야 하기 때문에 옵셔널 변수로 선언되어야 하고 당연히 상수가 아닌 변수 형태로 선언되어야만 한다.

위의 예시를 약한 참조로 적용시켜보자.

Apartment 클래스의 변수 tennat 의 참조를 약한 참조 방식으로 변경하였다.



이후 john 의 참조 값을 nil 로 변경하면,

더이상 Person 클래스에 대한 강한 참조가 존재하지 않기 때문에, 즉 reference count 가 0이기 때문에 해당 메모리는 해제되고 자연스레 tennat 변수의 참조 값 역시 nil 이 된다.

출력 결과를 보면 Person 클래스의 소멸자가 호출 된 것을 확인할 수 있다.




미소유 참조 (Unowned Reference)

미소유 참조 역시 약한 참조와 마찬가지로 reference count 가 증가하지 않는다.

미소유 참조는 약한 참조에 비해 참조하려는 인스턴스가 본인의 생명주기와 같거나 더 길때에 사용해야 한다. 왜냐하면 미소유 참조변수는 항상 값이 있는것으로 간주하기 때문에 ARC는 미소유 참조 값을 nil로 알아서 설정하지 않고 자연스레 미소유 참조 변수는 non-optional 변수이게 된다.

Customer 인스턴스는 CreditCard 인스턴스를 강하게 참조하고 있고 CreditCard 인스턴스는 Card 인스턴스를 미소유 참조로 참조하고 있다.



이 상황에서 john 의 참조 값을 nil 로 설정하면,

Customer 클래스 인스턴스에 대한 reference count 는 0이 되어 메모리가 정상 해제되면서 소멸자가 출력된다. 이후 CreditCard 에 대한 강한 참조 또한 사라지게 되므로 CreditCard 메모리 역시 정상 해제되어 소멸자가 출력되는 것을 확인할 수 있다.

profile
주니어 개발자까지 ☄️☄️

0개의 댓글