본문 바로가기
Languages/Swift

사당 iOS 스터디 5주차 - ARC

by 탄이. 2018. 8. 17.

CHAPTER 27 ARC

__27.1 ARC란

ARC는 더 이상 필요하지 않은 클래스의 인스턴스를 메모리에서 해제하는 방식으로 동작

가비지 컬렉션 기법과의 차이

  • 가장 큰 차이는 참조를 계산(count)하는 시점

  • ARC

    • 참조 카운팅 시점

      • 컴파일 시

    • 장점

      • 컴파일 당시 이미 인스턴스의 해제 시점이 정해져 있어서 인스턴스가 언제 메모리에서 해제될지 예측할 수 있습니다.

      • 컴파일 당시 이미 인스턴스의 해제 시점이 정해져 있어서 메모리 관리를 위한 시스템 자원을 추가할 필요가 없습니다.

    • 단점

      • ARC의 작동 규칙을 모르고 사용하면 인스턴스가 메모리에서 영원히 해제되지 않을 가능성이 있습니다.

  • 가비지 컬렉션

    • 참조 카운팅 시점

      • 프로그램 동작 중

    • 장점

      • 상호 참조 상황 등의 복잡한 상황에서도 인스턴스를 해제할 수 있는 가능성이 더 높습니다.

      • 특별히 규칙에 신경 쓸 필요가 없습니다.

    • 단점

      • 프로그램 동작 외에 메모리 감시를 위한 추가 자원이 필요하므로 한정적인 자원 환경에서는 성능 저하가 발생할 수 있습니다.

      • 명확한 규칙이 없기 때문에 인스턴스가 정확히 언제 메모리에서 해제될지 예측하기 어렵습니다.

클래스의 인스턴스를 생성할 때마다 ARC는 그 인스턴스에 대한 정보를 저장하기 위한 메모리 공간을 따로 또 할당합니다.

그 메모리 공간에는 인스턴스의 타입 정보와 함께 그 인스턴스와 관련된 저장 프로퍼티의 값 등을 저장

그 후에 인스턴스가 더 이상 필요 없는 상태가 되면 인스턴스가 차지하던 메모리 공간을 다른 용도로 활용할 수 있도록 ARC가 메모리에서 인스턴스를 없앱니다.

그런데 만약 아직 더 사용해야 하는 인스턴스를 메모리에서 해제시킨다면 인스턴스와 관련된 프로퍼티에 접근하거나 인스턴스의 메서드를 호출할 수 없습니다.

게다가 인스턴스에 강제로 접근하려고 하면 잘못된 메모리 접근으로 인해 프로그램이 강제 종료될 확률이 큽니다.

인스턴스가 지속해서 필요한 상황에서 ARC는 인스턴스가 메모리에서 해제되지 않도록 인스턴스 참조 여부를 계속 추적

다른 인스턴스의 프로퍼티나 변수, 상수 등 어느 한 곳에서 인스턴스를 참조한다면 ARC가 해당 인스턴스를 해제하지 않고 유지하는 명분이 된다는 것을 명심해야 한다

__27.2 강한참조

인스턴스가 계속해서 메모리에 남아있어야 하는 명분을 만들어 주는 것이 바로 강한참조

인스턴스는 참조 횟수가 0이 되는 순간 메모리에서 해제되는데, 인스턴스를 다른 인스턴스의 프로퍼티나 변수, 상수 등에 할당할 때 강한참조를 사용하면 참조 횟수가 1 증가

강한참조를 사용하는 프로퍼티, 변수, 상수 등에 nil을 할당해주면 원래 자신에게 할당되어 있던 인스턴스의 참조 횟수가 1 감소

참조의 기본은 강한참조이므로 별도의 식별자를 명시하지 않으면 강한참조

27.2.1 강한참조 순환 문제

  • 인스턴스끼리 서로가 서로를 강한참조할 때를 강한참조 순환(Strong Reference Cycle)

__27.3 약한참조

강한참조와 달리 자신이 참조하는 인스턴스의 참조 횟수를 증가시키지 않습니다.

weak 키워드를 써주면 그 프로퍼티나 변수는 자신이 참조하는 인스턴스를 약한참조합니다.

약한참조를 사용한다면 자신이 참조하는 인스턴스가 메모리에서 해제될 수도 있다는 것을 예상해볼 수 있어야 합니다.

참조 횟수를 증가시키지 않았기 때문에 그 인스턴스를 강한참조하던 프로퍼티나 변수에서 참조 횟수를 감소시켜 0으로 만들면 자신이 참조하던 인스턴스가 메모리에서 해제되기 때문

약한참조와 상수, 옵셔널

  • 약한참조는 상수에서 쓰일 수 없습니다.

    • 자신이 참조하던 인스턴스가 메모리에서 해제된다면 nil이 할당될 수 있어야 하기 때문

  • nil이 할당될 수 있어야 하므로 약한참조는 항상 옵셔널

  • 즉, 옵셔널 변수만 약한참조를 할 수 있습니다.

  • 강한참조 순환 문제를 약한 참조로 해결

    • 인스턴스가 메모리에서 해제될 때, 자신의 프로퍼티가 강한참조를 하던 인스턴스의 참조 횟수를 1 감소시킨다는 것을 알 수 있습니다.

    • 약한참조를 하는 프로퍼티는 자신이 참조하는 인스턴스가 메모리에서 해제되면 자동으로 nil을 할당한다는 것을 알 수 있습니다.

__27.4 미소유참조

미소유참조(Unowned Reference)는 인스턴스의 참조 횟수를 증가시키지 않습니다.

약한참조와 다르게 자신이 참조하는 인스턴스가 항상 메모리에 존재할 것이라는 전제를 기반으로 동작

즉, 자신이 참조하는 인스턴스가 메모리에서 해제되더라도 스스로 nil을 할당해주지 않는다.

그렇기 때문에 미소유참조를 하는 변수나 프로퍼티는 옵셔널이나 변수가 아니어도 됩니다.

런타임 오류가 발생하지 않도록, 미소유참조는 참조하는 동안 해당 인스턴스가 메모리에서 해제되지 않으리라는 확신이 있을 때만 사용

unowned 키워드를 써주면 그 변수(상수)나 프로퍼티는 자신이 참조하는 인스턴스를 미소유참조

__27.5 미소유참조와 암시적 추출 옵셔널 프로퍼티

서로 참조해야 하는 프로퍼티에 값이 꼭 있어야 하면서도 한번 초기화되면 그 이후에는 nil을 할당할 수 없는 조건을 갖추어야 하는 경우

미소유 참조와 암시적 추출 촙셔널 프로퍼티의 활용

  • 암시적 추출 옵셔널 프로퍼티는 이니셜라이저의 2단계 초기화 조건을 충족시키기 위해 사용

  • 미소유참조 프로퍼티는 약한참조를 사용할 수 없는 경우(옵셔널이 아니어야 하거나 상수로 지정해야 하는 경우)에 강한참조를 피하기 위하여 사용

__27.6 클로저의 강한참조 순환

클로저를 호출하면 그 때 클로저는 자신의 내부에 있는 참조 타입 변수 등을 획득

클로저는 자신이 호출되면 언제든지 자신 내부의 참조들을 사용할 수 있도록 참조 횟수를 증가시켜 메모리에서 해제되는 것을 방지하는데, 이때 자신을 프로퍼티로 갖는 인스턴스의 참조 횟수도 증가시킵니다.

이렇게 강한참조 순환이 발생하면 자신을 강한참조 프로퍼티로 갖는 인스턴스가 메모리에서 해제될 수 없습니다.

self 프로퍼티와 참조 횟수

  • 클로저 내부에서 self 프로퍼티를 여러 번 호출하여 접근한다고 해도 참조 횟수는 한 번만 증가

27.6.1 획득목록

  • 획득목록은 클로저 내부에서 참조 타입을 획득하는 규칙을 제시해줄 수 있는 기능

    • 클로저 내부의 self 참조를 약한참조로 지정할 수도, 강한참조로 지정할 수도 있다는 뜻

    • 획득목록을 사용하면 때에 따라서, 혹은 각 관계에 따라서 참조 방식을 클로저에 제안할 수 있습니다.

  • 획득목록은 클로저 내부의 매개변수 목록 이전 위치에 작성

  • 획득목록은 참조 방식과 참조할 대상을 대괄호([])로 둘러싼 목록 형식으로 작성하며 획득목록 뒤에는 in 키워드

  • 획득목록에 명시한 요소가 참조 타입이 아니라면 해당 요소들은 클로저가 생성될 때 초기화 됩니다

    • a(획득목록에 명시한 요소)는 클로저가 생성되었을 때 획득한 값을 갖지만, b는 변경된 값을 사용하는 것을 확인할 수 있습니다.

      • a 변수는 클로저가 생성됨과 동시에 획득목록 내에서 다시 a 라는 이름의 상수로 초기화된 것

  • 참조 타입의 획득목록 동작

    • 참조 타입은 획득목록에서 어떤 방식으로 참조할 것인지, 강한획득, 약한 획득, 미소유획득 중에 정해줄 수 있습니다.

    • 또 획득의 종류에 따라 참조 횟수를 증가시킬지 결정할 수 있습니다.

    • 다만 약한획득을 하게 되면 획득목록에서 획득하는 상수가 옵셔널 상수로 지정된다는 것




      참고


      야곰의 스위프트 프로그래밍 https://book.naver.com/bookdb/book_detail.nhn?bid=12571019


댓글