ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ARC (Automatic Reference Counting)
    Swift 2021. 1. 11. 13:32

    개인적으로 공부하며 정리하는 블로그 입니다.
    오류나 부족한 부분이 있을 수 있으니 감안하여 봐주시고 아낌없는 조언 감사드립니다 :D

     

    면접 단골질문! 오늘은 ARC에 대해 알아보겠습니다.

    ARC가 뭔가요? 

    라는 질문에 얼마나 대답할 수 있으신가요? 저는 수박 겉핥기식으로만 알고 있었는데요. 오늘 제대로 정리해보려고 합니다.
    "어.. 그거 레퍼런스 카운트 늘리고 줄이면서 자동으로 메모리 관리해주는 거잖아요, weak, unowned 있고 그거.... "
    대략적으로는 알겠는데 막상 설명하려고 하면 자꾸 두리뭉실해지는 이녀석... 오늘은 해결해봅시다 🔥

     


    ARC (Automatic Reference Counting)

    ARC는 자동으로 메모리를 관리해주는 컴파일러의 기능입니다. 인스턴스에 대한 메모리 관리를 컴파일러가 대신 해줘서 개발자는 다른 부분에 더 집중할 수 있도록 하기 위해 등장했습니다. 

    "Automatic Reference Counting (ARC) is a compiler feature that provides automatic memory management of Objective-C objects."
    - Transitioning to ARC Release Notes 참고

    "ARC is supported in Xcode 4.2 for OS X v10.6 and v10.7 (64-bit applications) and for iOS 4 and iOS 5. Weak references are not supported in OS X v10.6 and iOS 4."

    라고 나와있는 걸 보면 Objective-C를 사용하던 iOS 4, iOS 5 시절부터 등장한 개념인 것 같습니다. 애플은 이런 식의 노력을 참 많이 하는 것 같아요. 스레드 관리, 메모리 관리 같은 로우 레벨의 작업을 시스템이 처리해주게 만들어서 개발자는 보다 상위 작업에 집중할 수 있게 해주는거죠. 몰라도 사용할 수 있는 것들이 많아져서 편하지만 그만큼 모르는 게 많아지는 것 같기도 해요...

    메모리 관리

    아무튼 본론으로 돌아가서 핵심은 예전에는 개발자가 일일이 해줘야 했던 메모리 관리를 ARC라는 방식에서는 더 이상 직접하지 않아도 된다는거에요. Swift에서는 기본적으로 적용되어 있지만 Objective-C 에서는 선택사항이었던거죠.

    그럼 여기서 말하는 메모리 관리는 뭘 의미할까요? 

    https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/MemoryMgmt.html#//apple_ref/doc/uid/10000011i


    class 같은 참조 타입(reference type)의 변수들은 heap 영역의 메모리를 참조해서 사용하게 되죠? 따라서 위와 같이 메모리를 할당하고, 참조하고 해제하는 등의 작업들이 필요합니다.  ARC가 나오기 전에는 이런 작업들을 직접 해줘야 했는데, (이를 MRC(Manual Reference Counting)라고도 한답니다) ARC에서는 더 이상 그런 코드들을 쓸 필요가 없어진거에요 :)

    ARC는 인스턴스의 참조 횟수(Reference Count, 위 그림의 retain count)를 세고 있다가 0이 되면 자동으로 메모리를 해제시켜줍니다. 기본적으로 생성되거나 참조될 때 참조 레퍼런스 카운트를 증가시키고 해제되면 감소시킵니다.

    이렇게 ARC의 등장으로 아래 그림처럼 복잡했던 코드들을 줄여줄 수가 있게된거죠 !

    https://developer.apple.com/library/archive/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

     

    메모리 릭

    너무 편리하고 좋은 기능인데 몇 가지 주의해서 사용해야 할 경우가 있어요. 직접 관리하지 않기 때문에 ARC가 제대로 메모리를 해제시켜주지 않으면 사용하지 않는 메모리가 계속 남아있을 수 있겠죠? 이는 한정된 메모리 환경에서 동작해야하는 앱에서는 특히나 치명적일 수 있습니다.

    구체적인 상황은 공식문서에서 자세하게 다루고 있으니 여기선 좀 더 크게크게 살펴볼게요.
    쉽게말해 참조 횟수가 0일거 같은데? 실제로는 0이 되지 못하면 메모리에서 해제되지 않는거에요.

    문서의 예제처럼,
    Person(참조횟수 1)이 있고 Apartment(참조횟수 1)가 있는데,
    Person도 Apartment를(Apartment 참조횟수 2), Apartment도 Person을(Person 참조횟수 2) 변수로 참조하고 있으면, 
    Person과 Apartment를 해제(각각 참조횟수 -1) 해도 Reference count가 아직 1 이여서 해제되지 못하고 남아있게 되는거죠.

    또 Swift에서는 closure도 참조 타입인데요, closure 안에서 외부의 어떤 객체(가령 self)를 참조하는 경우도 위와같은 상황이 일어날 수 있겠죠?? 

    weak, unowned

    그래서 등장한 개념이 weak, unowned 입니다. 위와 같은 상황을 만들지 않기 위해 참조 횟수를 늘리지 않고 참조하고 싶었던거죠! 
    의도에 충실하게 둘다 참조 횟수를 늘리지 않습니다. 이제 반대로 위의 방식처럼 참조 횟수를 늘리는 방식은 strong 참조 방식이라고 부를 수 있겠네요.

    이제 남은 건 둘의 차이만 알아보면 되겠죠??

    weak는 이름처럼 약하게 참조하고 있다가 참조 횟수가 0이 되면 끊어버리겠다는거에요. 참조 카운트가 0이 되면 컴파일러는 weak로 참조하고 있는 변수에 nil을 할당해준답니다. 그러니 자연스럽게 weak 변수는 nil이 될 수 있는 optional 타입이어야겠죠? 나중에 '할당' 해줘야 하니 값을 바꿀 수 있는 var 이어야 하구요 :) 

    따라서 weak는 nil인지 체크를 통해 아직 메모리에 남아있는지 아닌지 확인해서, 비교적 안전하게 사용할 수 있습니다. 옵셔널로 그냥 사용하면 최악의 경우에 메모리가 해제되서 제대로 동작하지 않을 수도 있지만, 큰 문제까지는 생기지 않는거죠.

    이와 달리 unowned는 소유하지 않는다는 이름처럼, 내놓은 자식이에요. 만들어 놓고 신경쓰지 않겠다는거죠. weak와 달리 참조 카운트가 0으로 메모리에서 해제 되어도 별다른 처리를 해주지 않습니다. 이를 모르고 해제된 메모리에 접근하려고 하면 크래시가 발생할 수 있습니다. weak에서는 최악의 경우에 동작 안 하고 말았지만 unowned는 앱이 죽어버릴 수도 있겠죠? 따라서 메모리가 해제되지 않았다고 확실히 보장할 수 있는 경우에만 사용해야 합니다. 그래서 참조할 객체가 최소 나보다 lifecycle이 길거나 같은 경우에 사용하라고 하네요. 

    weak는 참조하는 걸 알고 있다가 찾아가서 일일이 nil로 바꿔줘야 하기 때문에 아무래도 unowned 보다는 좀 더 추가 작업들이 필요하겠죠? 따라서 unowned보다 안전하지만 오버헤드가 좀 있고 unowned는 조금 위험하긴 하지만 가볍고 옵셔널도 처리해주지 않아도 된다는 장점이 있습니다.

     

    미약하지만 조금이라도 도움이 되셨다면 좋겠네요 :)

    감사합니다!

     

     

    참고

    Automatic Reference Counting - Swift.org

    Transitioning to ARC Release Notes   

    About Memory Management

     

    'Swift' 카테고리의 다른 글

    defer  (0) 2020.09.21
    순수함수 Pure function  (0) 2020.08.04
    람다 λ lambda  (0) 2020.08.04
    Reduce  (0) 2020.08.04
    ~= 연산자 in Swift  (0) 2020.07.07

    댓글

Designed by Tistory.