[ swift ] ARC와 MRC의 개념

sonny·2024년 12월 2일
3

TIL

목록 보기
59/133
post-thumbnail

메모리구조와 자료구조 내용에 대한 블로그를 작성할 때 전체적으로 ARC에 대한 부분을 공부한 적이 있다.

이번에는 ARC와 MRC의 개념에 대해 알아보려고 한다.

ARC와 MRC는 메모리 관리 방식으로 객체의 생명주기를 관리하는 역할을 한다는 건 같다.

둘은 비슷한 목적을 가지고 있지만 구현과 사용 방식에서 차이가 있는데, 한 번 알아보자.


1. MRC (Manual Reference Counting)

  • 의미
    Manual Reference Counting은 프로그래머가 직접 메모리 관리 코드를 작성하여
    객체의 참조 카운트를 조작하는 방식이라고 한다.
    Objective-C에서 사용되던 방식으로 retain, release, autorelease와 같은 메서드를 통해
    참조 카운트를 관리를 한다.

  • 특징
    프로그래머가 객체의 생성, 소유권 이전, 해제를 명시적으로 처리해야 하고,
    메모리 누수(memory leak) 또는 잘못된 접근(segmentation fault)이 발생하기가 쉽다.
    잘 작성된 코드에서는 효율적일 수 있으나, 복잡한 경우 관리가 어려워진다.

  • 코드 예제 (Objective-C)

    MyClass *obj = [[MyClass alloc] init]; // 참조 카운트 1 증가
    [obj retain]; // 참조 카운트 2로 증가
    [obj release]; // 참조 카운트 1로 감소
    [obj release]; // 참조 카운트 0이 되어 메모리 해제

2. ARC (Automatic Reference Counting)

  • 의미
    Automatic Reference Counting은 컴파일러가 메모리 관리를 자동으로 처리해주는 방식이다.
    Swift와 최신 Objective-C에서 사용되며, 프로그래머가 명시적으로 참조 카운트를 관리할 필요가 없다.

  • 특징
    메모리 관리 코드가 없어도 컴파일러가 자동으로 retainrelease를 포함하면서,
    코드가 간결해지고 메모리 누수 가능성이 줄어든다.
    여전히 순환 참조를 조심해야 하는 부분이 있지만, 이를 해결하기 위해 weakunowned 키워드를 사용할 수 있다.
    성능이 MRC와 거의 유사하며, 유지보수성이 훨씬 높다.

  • 코드 예제 (Swift):

    class MyClass {
        init() {
            print("생성")
        }
        deinit {
            print("소멸")
        }
    }
    
    var obj1: MyClass? = MyClass() // 참조 카운트 1
    var obj2 = obj1               // 참조 카운트 2
    obj1 = nil                    // 참조 카운트 1
    obj2 = nil                    // 참조 카운트 0 -> 메모리 해제

MRC와 ARC의 차이점을 정리한 표

구분MRC (Manual Reference Counting)ARC (Automatic Reference Counting)
메모리 관리프로그래머가 직접 관리컴파일러가 자동으로 처리
사용 방식retain, release, autoreleaseweak, unowned 키워드로 순환 참조 해결
오류 가능성높은 가능성 (누수, 잘못된 해제)낮은 가능성 (컴파일러가 관리)
유지보수복잡하고 어렵다간단하고 유지보수성이 높다
성능최적화된 코드에서는 빠르다성능은 MRC와 거의 유사

MRC 너무 구식 아닌가?

MRC(Manual Reference Counting)는 현재 기준으로 보면 구식이고,

직접 메모리를 관리해야 하기 때문에 사용성이 불편하다는 단점이 있다.

Swift와 같은 현대 언어들은

ARC(Automatic Reference Counting)와 같은 자동화된 메모리 관리 기법을 기본으로 채택하고 있는데..

그래도 MRC를 이해하는 것이 완전히 쓸모없지는 않다고 한다.

왜냐하면 메모리 관리의 기본 원리를 배우는 데 도움을 주고

오래된 Objective-C 코드나 저수준 언어에서 레거시 시스템을 다룰 때 유용할 수 있기 때문이다.


ARC와 MRC의 관계

  • ARC는 MRC의 단점을 보완한 방식이다.

  • MRC에서 프로그래머가 수동으로 작성했던 참조 카운트 관리 코드를 컴파일러가 자동으로 삽입하여 ARC가 동작한다.

  • 결국 ARC는 MRC의 원리를 기반으로 하지만 이걸 자동화시켜 사용 편의성과 안정성을 향상시킨 개념이라 볼 수 있다.


순환 참조와 해결 방법 (ARC에서 중요)

순환 참조는 ARC에서도 관리가 필요한 중요한 문제다.

두 객체가 서로를 강하게 참조하면 참조 카운트가 0이 되지 않아 메모리에서 해제되지 않는다.

이걸 방지하기 위해 weakunowned 키워드를 사용하는데,

  • weak: 참조 카운트를 증가시키지 않는 비소유 참조. 참조 대상이 해제되면 nil로 설정된다.

  • unowned: 참조 카운트를 증가시키지 않는 비소유 참조. 대상이 해제되어도 nil로 설정되지 않으므로, 해제된 객체에 접근하면 런타임 에러가 발생한다.

순환 참조 예시

class A {
    var b: B?
}

class B {
    weak var a: A? // weak를 사용하여 순환 참조 방지
}

var objA: A? = A()
var objB: B? = B()
objA?.b = objB
objB?.a = objA
objA = nil // 모든 참조가 해제됨
objB = nil

요약하자면,

  • MRC: 프로그래머가 수동으로 메모리 관리함
  • ARC: MRC를 자동화하여 컴파일러가 관리함
  • ARC는 MRC의 원리를 기반으로 하며, 메모리 관리의 오류 가능성을 줄이고 유지보수성을 높이는 역할을 함.
  • ARC를 사용할 때도 순환 참조를 방지하기 위한 weakunowned의 사용법을 이해하는 것이 중요함.

음...

메모리 관리가 제대로 되지 않으면 애플리케이션이 예기치 않게 종료되거나, 메모리 누수 같은 문제가 발생할 수 있다.

거기서 ARC가 이를 얼마나 잘 처리해주는지 알게 되었고,

프로그래밍의 생산성을 크게 향상시킨다는 점을 깨달았다.

ARC에서도 weak나 unowned를 사용하지 않으면 순환 참조 문제가 발생할 수 있는데,

이걸 해결하는 방법을 익히며 메모리 관리의 세부적인 부분을 이해해볼 수 있었다. (아직 어렵다 그래도 전보단 이해했다)

MRC는 지금 보면 불편하고 구식이라 생각했지만,

ARC와 같은 자동화 기술이 등장하기 전에는 중요한 메모리 관리 기법이었다는 걸 알았고

MRC의 원리를 이해하면 ARC의 내부 동작 방식에 대해 더 깊게 알 수 있다고 하니 더 완벽하게 이해하려 해야겠다는 생각이 든다.

ARC와 MRC를 비교하며 메모리 관리 기술이 참 많이 발전했구나 싶기도 하고,,

그래도 MRC의 기본 원리를 이해하면 ARC의 한계나 예외 상황을 더 잘 다룰 수 있게 된다고 하니 둘다 잘 알아야겠지.

profile
iOS 좋아. swift 좋아.

0개의 댓글

관련 채용 정보