study record

[Swift] Swift 메모리 관리 - ARC란? 본문

Swift/스위프트 정리

[Swift] Swift 메모리 관리 - ARC란?

asong 2022. 5. 18. 17:02

참조 타입은 하나의 인스턴스가 참조를 통해 여러 곳에서 접근하기 때문에 언제 메모리에서 해제되는가가 중요한 문제이다. 적절한 시점에 인스턴스가 해제되지 않으면 한정적인 메모리 자원을 낭비하게 되고, 이는 성능 저하로 이어질 수 있다.

 

Swift는 프로그램의 메모리 사용을 관리하기 위해 메모리 관리 기법ARC(Automatic Reference Counting)을 사용한다.

 

ARC가 관리해주는 Reference Counting (참조 횟수 계산)은 참조 타입인 클래스의 인스턴스에만 적용된다.
구조체나 열거형은 값 타입으로 다른 곳에서 참조하지 않기 때문에 ARC로 관리할 필요가 없다.

 

ARC란?

ARC는 자동으로 메모리를 관리해주는 방식이다. 대부분의 경우 메모리 관리는 Swift에서 그냥 작동하기 때문에 개발자는 메모리 관리에 대해 신경을 덜 쓸 수 있다.

 

스택(Stack) 메모리에 저장된 데이터는 자동으로 제거되기 때문에 특별한 관리가 필요 없다.

하지만 힙(Heap) 메모리에 저장된 데이터는 필요하지 않은 시점에 직접 제거해야만 한다. 따라서 메모리 관리 모델이 힙에 저장된 데이터를 관리한다.

 

값 타입(Value Type)은 스택 메모리에, 참조 타입(Reference Type)은 메모리에 저장된다.

값 타입: Struct, Enum

참조 타입: Class, Closure

힙은 클래스, 클로저 등의 참조형 자료들이 머무는 공간이자, 개발자가 동적으로 할당하는 메모리 공간이므로 관리가 필요하다.

관리를 위해서 힙 영역에 참조형 자료들이 얼마나 참조되고 있는지 카운팅하고 이에 따라 메모리를 할당 및 제거하면 된다. 이것을 자동으로 해주는 것이 ARC이다.

 

인스턴스 생성

클래스의 인스턴스가 생성되면 해당 인스턴스의 정보는 HeapObject라는 struct로 관리가 된다.

ARC의 메커니즘은 Swift Runtime이라는 라이브러리에 구성되어 있는데, Swift Runtime은 동적 할당되는 모든 object를 HeapObject라는 struct로 표현한다. 또한 HeapObject에서는 Swift에서 객체를 구성하는 모든 데이터, 즉 reference count와 type meta data를 포함하고 있다.

 

인스턴스 해제

ARC는 인스턴스가 더 이상 필요하지 않다면 해당 인스턴스를 메모리에서 해제시킨다.

알고보니 인스턴스가 필요했다면 인스턴스의 프로퍼티와 함수에 접근이 불가하고, 강제 접근시 앱이 죽을 수 있다.

따라서 ARC는 해당 인스턴스를 참조하는 다른 인스턴스의 프로퍼티나 변수, 상수 등의 개수를 세고, 해당 인스턴스에 대한 활성 참조가 1개 이상 존재하는 한 인스턴스를 메모리에서 없애지 않는다. heapObject의 reference count가 활성 참조이다.

 

 

ARC vs 가비지 컬렉션

가비지 컬렉션은 자바, C#에서 사용되는 메모리 기법이다.

둘의 가장 큰 차이점은 참조를 카운팅하는 시점이다.

ARC는 컴파일 시에, 가비지 컬렉션은 프로그램 동작 중에 카운팅한다.

 

가비지 컬렉션과 다르게 ARC는 컴파일과 동시에 인스턴스를 메모리에서 해제하는 시점을 결정하기 때문에 ARC를 이용해 원하는 방향으로 메모리 관리를 효율적으로 하기 위해서는 ARC에 명확한 힌트를 남겨야 한다.

 

 

MRC 메모리 관리(Manual Reference Counting)

예전 Obj-C는 retain, release, autorelease 등을 통해 수동으로 메모리 관리를 했다.

retain -> retain count(= reference count) 증가를 통해 현재 Scope에서 객체가 유지되는 것을 보장

release -> retain count(= reference count)를 감소시킴. retain 후에 필요없을 때 release 한다.

 

ARC는 자동으로 retain, release를 삽입해서 retainCount를 관리하고, 0이 될 때 deinit을 호출하여 메모리 해제를 시킨다.

 

 

'retain count'와 'reference count'의 차이

retain count객체에 의해 내부적으로 유지되는 카운트이다. 얼마나 많이 불균형적인 retain이 이 객체에 보내지고 있는지이다. 

reference count외부적인 사실이다. 얼마나 많은 객체들이 이 객체에 참조를 가지는지.

 

메모리 관리의 목표는 이 두 숫자를 항상 같게 유지하는 것이다.

 

 

참고

- https://velog.io/@ssionii/Swift-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B4%80%EB%A6%AC-a.k.a-ARC-%EC%97%90-%EB%8C%80%ED%95%B4-%EC%95%84%EB%9D%BC%EB%B3%B4%EC%9E%90-ARC%EB%9E%80

- https://onelife2live.tistory.com/10

- https://sujinnaljin.medium.com/ios-arc-%EB%BF%8C%EC%8B%9C%EA%B8%B0-9b3e5dc23814

- https://stackoverflow.com/questions/53890203/the-difference-between-retain-count-and-reference-count-in-swift