앞선 포스트에서 다뤘던 MRC를 통해서 iOS의 메모리가 관리되고 있었고, Objective-C 2.0이 발표되면서 ARC와 GC이 등장했다.
시간이 지나면서 MRC는 사용할 수 없게 막혔고, GC 또한 deprecated되어 현재는 ARC 만을 메모리 관리 방식으로 사용할 수 있다.
GC (Garbage Collection)
가비지 컬렉션은 이름 그대로 쓰레기를 수집하듯 런타임에 사용되지 않는 메모리를 쭉 찾아내서 해제시키는 방식이다.
가비지 컬렉션은 크게 두 가지의 매커니즘을 통해 수행된다.
- Stop the world
- Mark and Sweep
즉, GC를 수행하기 위해 나머지 모든 스레드의 수행을 일시 중단(Stop)하고 해제시키면 안되는 인스턴스를 모두 표시(Mark)한 후, 참조되지 않는 인스턴스를 모두 해제(Sweep)시킨다.
객체 간의 참조 관계를 복잡하게 고려할 필요 없이 GC가 수행되는 시점에 알아서 필요 없는 인스턴스를 모두 정리해주는 것이 GC의 장점이라고 할 수 있다.
하지만 이를 수행하기 위해서 잠시 모든 스레드를 중단 시켜야하기 때문에 사용자의 사용 경험에 영향을 줄 수 있다.
런타임에 해당 작업을 수행하는 것은 아무래도 컴파일 시간에 RC를 계산하는 Reference Counting과 퍼포먼스에서 차이가 날 수 밖에 없다.
실제로 안드로이드 OS에서 GC를 사용하고 있으며, iOS에 비해 물리적인 메모리 용량이 많아도 버벅거린다는 평을 많이 받았던 이유이기도 하다.
현재는 iOS에서는 GC를 지원하지 않게 되었다.
ARC (Auto Reference Couting)
ARC는 iOS 5 이후 도입되었으며, MRC에서 개발자가 일일이 레퍼런스 카운트를 관리하던 부분을 어느 정도 해소한 방식이다.
객체 간의 관계에 따라 언제 메모리에서 해제할 지 컴파일 시간에 컴파일러가 미리 계산을 한다.
개발자가 직접 RC를 관리할 필요가 없어져서 편리해진 반면, 순환참조의 문제를 해결해야 하는 문제점이 있다.
ARC가 도입되면서 애플에서는 retain, release, dealloc의 명시적 호출을 사용할 수 없도록 막았으며, retainCount를 호출해서 현재 RC를 확인하는 메시지도 보낼 수 없다.
이는 해당 인스턴스가 autoreleasepool에서 해제될 예정인 경우, RC에 포함되지 않아서 정확한 RC를 확인할 수 없기 때문이라고 한다.
참조 종류
ARC를 구현하기 위해서는 새로운 인스턴스를 참조하는 경우에 참조 방식을 잘 설정해야 한다.
참조 종류는 strong, weak, unowned로 나뉘어져 있으며, Objective-C에서는 strong, weak, assign에 해당한다.
- strong : 강한 참조이며, Reference Count를 증가시킨다.
- weak : 약한 참조이며, Reference Count를 증가시키지 않는다. 해당 인스턴스는 nil이 될 수 있으므로 optional이여야 한다.
- unowned : Reference Count를 증가시키지 않으며, nil이 되지 않는 것을 전제하기 때문에 optional이 아니다.
만약 서로 다른 두 인스턴스가 strong으로 참조를 하면 서로 RC가 감소되지 않아 결국 둘 다 해제되지 않는 경우가 발생할 것이다.
이를 순환 참조라고 부르며, 자세한 내용은 다음 포스트에서 따로 다루겠다.
weak과 unowned의 차이는 nil이 될 수 있는지의 차이로 볼 수 있다.
weak은 인스턴스가 해제되면서 nil이 될 수 있으며, 그렇기 때문에 optional이여야 한다.
반면, unowned는 인스턴스가 해제되지 않는 것을 전제하기 때문에 optional이 아니다.
따라서 unowned로 선언되었으나 인스턴스가 해제되어 버리면 댕글링 포인터가 되어 비정상적인 수행이 일어날 수 있다.
그렇다면 굳이 unowned를 쓰는 이유는 무엇일까.
weak은 자체 사이드 테이블을 구성해서 오버헤드의 가능성이 있다고 한다.
따라서 primitive type인 char, int, bool 등의 타입은 인스턴스가 메모리에 있는 것을 확신할 수 있기 때문에 이를 unowned로 설정하면 퍼포먼스 향상에 도움이 될 수 있다.
다음 포스트에서는 ARC의 문제점으로 거론되는 순환 참조에 대해 다뤄보겠다.
개인적인 공부를 위해 작성한 내용이므로 틀린 내용이나 수정이 필요한 부분이 있을 수 있으니 감안하고 봐주시면 감사하겠습니다.
'iOS' 카테고리의 다른 글
[iOS] MVC, MVP, MVVM 패턴 (1) | 2024.01.22 |
---|---|
[iOS] MRC와 iOS의 메모리 관리 방식 (0) | 2024.01.09 |