Automatic Reference Counting vs Garbage Collection

devapploper·2024년 7월 15일

ARC

  • Automatic Reference Counting 의 약자
  • 스위프트의 메모리 관리 체계
  • 메모리에 인스턴스별로 레퍼런스 카운트를 기억하고 있다가 0이 되면 해당 인스턴스를 메모리에서 해제함
  • 컴파일 시점에 컴파일러가 retain 혹은 release 등의 오브젝트 코드를 추가하고 런타임에 레퍼런스 카운트를 올리거나 내림. 이 카운트가 0이 되면 해당 인스턴스를 메모리에서 해제함
  • 장점:
    • 사용자가 인스턴스의 메모리 할당, 해제, 그리고 확보를 일일이 관리하지 않아도 되고 인스턴스의 참조 수만 관리하면 됨
    • Deterministic: Class Destructor이 예상 가능한 시점에 호출됨
  • 단점:
    • 운영체제에서 인스턴스의 참조 수를 관리하기 위한 메모리 자원의 확보가 필요함
    • 이 방법 또한 완벽하지 않아서 개발자의 부주의로 인해 retain cycle/circular reference 등을 관리하지 않으면 메모리 누수로 이어질 수 있음
// 이랬던걸
func doSomething() -> Object {
    let thing1 = Object(name: "foo")
    var thing2 = Object(name: "bar")
    thing2 = Object(name: "baz")
    return thing2
}

// 컴파일러가 이렇게 변환한다
func doSomething() -> Object {
    let thing1 = Object(name: "foo")
    __retain(thing1) // increment reference count so thing1 sticks around

    var thing2 = Object(name: "bar")
    __retain(thing2) // increment reference count so thing2 sticks around

    let oldThing2 = thing2 // thing2 gets replaced on the next line
    thing2 = Object(name: "baz")
    __release(oldThing2) // get rid of the thing that got overwritten
    __retain(thing2) // hold onto the new thing that replaced it

    __release(thing1) // end of scope, so nothing else will use thing1
    return __autorelease(thing2) // relinquish ownership of thing2,
        // but only upon handing ownership over to our caller
}

// reference: https://stackoverflow.com/a/39379126

Garbage Collection

  • 가비지 컬렉터라는 런타임 프로그램이 사용 중인 객체들을 마킹하고, 메모리의 처음부터 끝까지 훑으면서 마킹된 객체가 있는 공간을 제외하고는 모두 해제시킴.

  • Java, C#, Go 등의 프로그래밍 언어에서 사용하는 메모리 관리 기법

  • 일반적으로 같이 거론되는 GC 동작 알고리즘들: Naive mark-and-sweep / tri-color marking

    • Naive mark-and-sweep
      • Mark 단계: 객체의 root부터 시작해서 직접적으로나 간접적으로나 참조 관계에 있는 모든 객체를 마킹함
      • Sweep 단계: 메모리에 할당된 모든 객체들을 하나씩 살피면서 마크가 있으면 그대로 두고, 없으면 해제시킴
    • Tri-color Marking:
      • 객체들을 White, Grey, Black 세가지 그룹으로 분류하고, white 그룹에 속해있는 객체들을 해제시킴
      • 상술한 Naive mark-and-sweep 방법은 진행시 프로그램이 일시정지해야하는 반면에 tri-color marking은 일부 과정만 제외하면 프로그램의 동작과 동시에 일어남 == 동시성
      • 많은 가비지 컬렉터 구현에서 naive mark-and-sweep보다는 tri-color marking를 추상화하여 사용 중
  • 장점:

    • 개발자가 직접 메모리 관리를 하지 않아도 됨
    • ARC와는 다르게 Retain Cycle/Circular Reference까지도 정리해줌
  • 단점:

    • 런타임에 실행되는 작업이기 때문에 충분한 메모리 공간 확보가 필요함
    • GC 작업 중에는 메모리를 사용할 수 없기 때문에 정지 상태가 됨
    • Non-deterministic: Class Destructor이 언제 불릴지 알 수가 없고 Class Destructor를 활용하는데 제한이 있을 수 있음. 실제로 Garbage Collector를 사용하는 언어 중에 destructor를 사용하지 못하게 막기도 함

iOS에서는 왜 GC가 아닌 ARC를 선택했을까?

  • GC는 런타임 프로세스로서 안그래도 적은 모바일 환경의 메모리 공간을 차지함.
  • GC는 동작 중에 다른 일을 하지 못하게 막기 때문에 기기 사용 중에 불편함을 겪을 수 있기 때문.
  • GC는 메모리가 넉넉하면 굉장히 효율적으로 동작하지만, 데스크탑이나 랩탑과는 달리 제한된 메모리 자원이 있는 모바일 환경에서는 오히려 느린 퍼포먼스를 보임.
    • 메모리는 사용 중이거나 사용 중이지 않거나 크면 클 수록 배터리 소모가 커서, 필요 이상의 메모리는 배터리 고갈을 유발하기 때문에 넉넉한 메모리 또한 좋은 선택이라고 할 수 없음.
  • ARC는 동작 특성상 런타임에 시스템 동작에 영향을 주지 않는 수준의 오버헤드이기 때문에 상대적으로 부드러운 사용자 경험을 제공함.

P.S. OS X Mountain Lion 에서 GC를 deprecate 했다는 내용이 있다는 걸로 봐서, 애플도 GC를 사용하다가 ARC로 완전히 입지를 굳힌걸로 보임 (레퍼런스)

profile
iOS, 알고리즘, 컴퓨터공학에 관련 포스트를 정리해봅니다

0개의 댓글