[WWDC21] ARC in Swift: Basics and beyond

brick·2023년 7월 27일
0

Watch WWDC 📽️

목록 보기
2/5
post-thumbnail

Object lifetimes and ARC

  • 객체의 lifetime은 초기화를 통해 시작하고 마직막 사용 후 끝난다.
  • ARC는 lifetime이 끝나면 객체의 할당을 해제한다.
  • ARC는 객체의 lifetime을 reference count를 사용해 추적한다.
  • Swift 컴파일러는 retain / release 연산자를 삽입한다.
  • Swift는 runtime에 reference count가 0 이면 할당을 해제한다.

  • 참조가 시작될 때 retain 삽입
  • 참조의 마지막 사용후 release 삽입

Compiletime

  • traveler1은 Traveler 객체에 첫번째 참조이다.
  • traveler1의 마지막 사용은 복사이다(traveler2에 복사)

  • traveler1의 마지막 사용 직후 Swift Compiler가 release를 삽입
  • retain을 삽입하지 않았는데, initialization이 reference count를 1로 설정해준다.

  • traveler2는 Traveler 객체의 또 다른 참조이다.
  • traveler2의 마지막 사용은 destination 업데이트 작업이다.

  • Swift Compiler는 참조가 시작될 때 retain 연산자를 삽입합니다.
  • 참조의 마지막 사용 직후 release 연산자를 삽입합니다.

Runtime

  • Traveler 객체가 heap에 생성되고 reference count 1로 설정

  • Traveler 객체의 추가 참조로 reference count 2로 증가

  • Traveler 1의 마지막 사용 후 reference count 1로 감소

  • traveler2의 destination 업데이트하는 마지막 사용 후 reference count 0으로 감소
  • referece count가 0 이므로 할당 해제할 수 있다.


  • Swift에서 객체의 lifetime은 사용 기반이다(use-based)
  • 객체의 초소 lifetime이 보장된다(초기화 후 시작 - 마지막 사용 후 끝)
    • C++이랑 다름
    • C++의 lifecycle은 '}' 에 도달했을 때 까지 보장됨

  • 실제로는 최소 관찰되는 lifetime은 최소 보장과 다르게 마지막 사용 이후에 종료된다.(HERE에서 해제됨)
    • retain, release 연산자로 관리돼서 차이날 수 있음
    • ARC 최적화에 따라 달라짐
    • 대부분의 경우 에서는 문제 안됨

  • Weak & unowned 참조, Deinitializer의 size-effects 를 활용하면 해결 가능

  • guranteed object lifetime 대신에 observed object lifetime에 의존하면 나중에 버그 생김



Observable object lifetimes

  • weak, unowned 참조를 사용하면 reference counting에 참여하지 않는다. 그래서 reference cycle을 해제하는데 많이 사용한다.

  • Account는 Traveler를 참조하고 Traveler는 Account를 참조한다.

  • Traveler 객체 생성

  • Traveler reference count: 1

  • Account 객체 생성
  • account가 traveler 참조
  • Traveler reference count: 2
  • Account reference count: 1

  • traveler가 account 참조
  • Traveler reference count: 2
  • Account reference count: 2

  • account의 마지막 사용
  • Traveler reference count: 2
  • Account reference count: 1

  • traveler의 마지막 사용
  • Traveler reference count: 1
  • Account reference count: 1

  • 순환 참조때문에 reference count 1씩 남음
  • 메모리에서 해제 안됨
  • 메모리 누수 발생

  • weak or unowned를 사용하면 참조중인 객체가 사용중에 메모리에서 해제될 수도 있습니다.

  • Account의 traveler를 weak로 선언해 순환 참조 방지

  • guaranted object lifetime이후에 약한 참조에 접근하거나 observed object lifetime에 의존하면 나중에 버그 발생

  • Account로 printSummary 메소드 이동
  • traveler의 name 과 points의 print는 우연이다(실패할 수있다.)
  • 메모리에서 해제된 traveler를 참조할 수 있다.

  • 강제 언랩핑대신 옵셔널 바인딩 사용
  • 옵셔널 바인딩은 문제를 더 악화시킨다.
    • crash 대신 silent bug 생성

  • weak, unowned reference를 안전하게 다루는 방법
  • 각각은 초기 구축 비용과 지속적인 유지 비용의 정도가 다릅니다.

  • withExtendedLifetime()을 사용하면 안전하게 객체의 lifetime을 연장할 수 있습니다.

  • scope의 마지막에 빈 withExtendedLifetime()을 놓아도됨

  • defer을 사용해도 됨

  • 쉽게 lifetime 버그 잡는거같지만 이 기술을 fragile 하고 정확성의 책임을 너에게 전달한다

  • 이러한 저근방식으로는 약한 참조가 버그를 발생시킬 가능성이 있는데 마다 withExtendedLifetime()을 사용해야된다.

  • withExtendedLifetime이 제어되지 않으면 유지 보수 비용을 증가시킬 수 있다.

  • printSummary()를 Traveler로 올겼고 printSummary()는 이제 강한참조를 통해서만 호출됩니다.
  • weak, unowned 참조는 성능 부담외에도 클래스 설계를 주의하지 않으면 문제를 일으킬 수 있다.

  • weak, unowned는 순환 참조를 피할 때만 사용해야되나??
  • 처음 부터 피하게 설계한다면??

  • Account class는 traveler의 personal information에만 접근하면됨.
  • traveler의 개인정보를 PersonalInfo라는 새로운 class로 이동
  • 추가 구현 비용이 들지만 잠재적인 객체 수명 버그를 제거하는 명확한 방법이다.

  • 객체의 수명을 관찰할 수 있는 다른 방법은 deinitializer의 side-effect이다.
  • 할당이 해제되지 전에 실행되고 side effect로 외부 프로그램에 영향을 줄 수 있다.
  • 외부 프로그램에 영향을 주는 연속 deinitializer를 작성한다면 버그로 이어질 수 있다.


  • deinitializer는 print하는 글로벌 사이드 이펙트 있다.
  • 오늘은 "Done traveling" 이후에 deinitializer 실행되지만 다음에는 전에 deinitializer가 실행될 수 있다.
  • ARC의 최적화에 따라 달라짐

  • Traveler class에 TravelMetrics class를 도입함.
  • Traveler 객체가 해제될 때, metric이 publish() 실행

  • computTravelInterest()와 verifyGlobalTravelMetric()의 순서가 상황에 따라 바뀐다.
  • 할당 해제후 computTravelInterest() 실행되면 nil 값으로 버그 발생

  • deinitializer의 사이드이펙트 안전하게 해결하는 방법

  • withExtendedLifetime() 사용

  • internal -> private로 변경

  • deinitializer 대신 defer 사용해 publish함
  • deinitializer는 검증만함
  • deinitializer의 사이드 이펙트를 제거하면 모든 잠재적 객체 수명 버그를 제거할 수 있다.

  • Xcode13 에서 "Optimize Object Lifetimes"이용 가능하다
  • ARC 최적화로 수명을 단축시킨다.

참고

0개의 댓글