ARC(Automatic Reference Counting)란?

2 minute read

✅ ARC(Automatic Reference Counting)란?

  • 말 그대로 자동으로 메모리를 관리해주는 방식입니다. ARC는 더이상 사용하지 않는 클래스의 인스턴스를 메모리에서 해제하는 방식으로 관리합니다.

ARC 는 참조 카운트를 관리하기 때문에 참조 타입인 클래스의 인스턴스에만 적용됩니다. 당연히 열거형, 구조체와 같은 것은 참조 카운트를 사용하지 않기 때문에 ARC 가 관리하지 않아도 됩니다.

✅ 왜 사용해요?

Swift 에서는 메모리 사용을 관리하기 위해서 ARC 를 사용합니다.

값 타입과 달리 참조 타입은 하나의 인스턴스가 참조를 통해 여러 곳에서 접근되기 때문에 적절한 시점에서 메모리에서 해제되지 않으면 한정적인 메모리 자원을 낭비하는 memory leak 이 발생합니다. 이는 성능 저하로 이어집니다.

✅ 이걸 어떻게 사용하나요?

  • ARC 는 클래스 인스턴스가 참조될 때(강한 참조 시) 레퍼런스 카운트를 증가시킵니다.
  • 참조하는 프로퍼티, 변수, 상수 등에 nil 을 할당해주면 레퍼런스 카운트가 감소시킵니다.

이때 레퍼런스 카운트가 0이 되는 순간 인스턴스를 메모리에서 해제합니다.

✅ 장/단점

핵심은 ARC는 인스턴스가 언제 메모리에서 해제되는지 컴파일과 동시에 결정할 수 있습니다.

👉 장점 :

  • 레퍼런스 카운팅 시점이 컴파일이다.
  • 그렇기 때문에 컴파일 시점에서 인스턴스의 해제 시점이 정해지기 때문에 언제 메모리에서 해제되는지 예측할 수 있다.
  • 이 점은 메모리 관리를 위한 시스템 자원을 추가할 필요가 없음을 의미한다.

(프로그램 동작 중 레퍼런스 카운팅 되는 가비지 컬렉션의 경우 메모리 감시를 위한 추가 자원이 필요하고, 이는 한정적인 자원 환경에서 성능 저하로 이어질 수 있다. 하지만, 상호 참조 상황 등의 복잡한 상황에서도 인스턴스를 해제할 수 있다는 장점이 있다.)

👉 단점 :

  • ARC 의 작동 규칙을 모르고 사용하면 메모리에서 해제되지 않을 가능성이 있다.

✅ Strong Reference Cycle

강한 참조(strong)

  • “인스턴스가 계속 사용되야 하기 때문에 메모리에 남아있어야 한다.” 라는 명분을 주는 것이 Strong Reference(강한 참조)입니다.
  • 위에서 언급한 레퍼런스 카운트가 증가될 때는 강한 참조인 경우에 해당합니다. 이 강한 참조는 별도의 식별자를 명시하지 않으면 강한 참조로 여겨집니다.

이때 어떤 상황에 대해서 클래스의 인스턴스의 사용이 끝났음에도 불구하고 레퍼런스 카운트가 0이 되지 않아 메모리에서 사라지지 않는 memory leak 이 발생하는 것을 강한참조 순환(strong reference cycle)라고 합니다.

❓ 언제 발생하나요?

  • 두 개 이상의 객체가 서로를 강하게 참조하여 발생하게 된다.
  • 변수에 인스턴스를 할당하며 생기는 레퍼런스 카운트 이외에 서로가 참조하면서 레퍼런스 카운트가 추가로 증가. nil 을 할당하더라도 레퍼런스 카운트가 0이 되지 않게 된다.

❓ 어떻게 해결하나요?

약한 참조, 미소유 참조를 사용하여 해결합니다.

약한 참조(weak)

  • weak 키워드를 앞에 선언하여 설정합니다.
  • 강한 참조와 달리 참조하는 인스턴스의 레퍼런스 카운트를 증가시키지 않습니다.
  • 약한 참조를 사용할 때는 메모리 상에서 인스턴스가 없어질 수 있는 즉, nil 이 될 수 있기 때문에 옵셔널이어야 합니다. 또한, 값이 변경될 수 있어야 하기 때문에 변수여야 합니다.
  • 약한참조에서는 메모리에서 해제되면 nil 이 할당되어야 하기 때문에 추적되어야 합니다. 이는 경우에 따라 오버헤드로써 적용될 수 있습니다.

미소유 참조(unowned)

  • unowend 키워드를 앞에 선언하여 설정합니다.
  • 약한 참조와 같이 레퍼런스 카운트를 증가시키지 않습니다.
  • 약한 참조와 달리 참조하는 인스턴스가 항상 메모리에 존재한다는 가정으로 동작합니다. 그래서 미소유 참조는 nil 이나 변수가 아니어도 됩니다.
  • 미소유 참조로 메모리 해제된 인스턴스를 접근하면 런타임 오류가 발생해서 강제 종료됩니다.
  • 미소유 참조는 반드시 참조하는 인스턴스가 존재한다는 관계에서 강한 참조 순환을 피하기 위해서 사용할 수 있습니다. 예를 들어, 사람이 신용카드를 가지지 않을 수 있지만, 신용카드는 사람이 존재한다는 확신이 있는 이와 같은 관계에서 사용됩니다.
  • 반드시 참조하는 인스턴스가 존재한다는 관계에 한해서 nil 이 될 상황은 없지만 강한 순환 참조를 방지 하기 위해서 weak 를 사용하면, 불필요한 추적이 오버헤드가 될 수 있습니다. 이를 unowned 를 사용하여 불필요한 추적을 없앨 수 있고, 관계의 의도를 코드로써 표현할 수 있는 장점이 있습니다.

출처

SWIFT 스위프트 프로그래밍 - 야곰

Unowned Optional References

Categories:

Updated: