ARC上
ARC(Automatic Reference Counting)
오늘은 Swift에서 앱의 메모리 사용을 관리하는 ARC에 대해서 알아보도록 하겠습니다! ARC는 iOS 개발하는 사람이라면 필수적으로 알아야하는 것 중 하나입니다. 어떤 언어를 사용하든 메모리 관리는 중요하기 때문이죠! 자바에서 GC를 사용하는 것처럼 Swift에선 메모리 관리로 ARC를 사용합니다.
ARC가 뭐야?
Objective-C 로 개발하던 시기에는 개발자가 직접 메모리 관리를 하였으나 ARC를 사용하면서 자동으로 참조 횟수를 관리가 가능해졌다. 메모리를 할당하면 참조 횟수가 자동으로 올라가고 더이상 사용되지 않는 인스턴스를 메모리에서 해지합니다. 참고로 참조 횟수는 클래스 타입의 인스턴스에만 적용되고 값 타입인 구조체 열거형 등에는 적용되지 않습니다.
동작 방법
- 클래스의 새 인스턴스를 만들 때마다 ARC는 인스턴스 정보를 담는데 필요한 적절한 크기의 메모리를 할당합니다. 이때 그 메모리는 인스턴스에 대한 정보와 관련된 저장 프로퍼티 값도 가지게 됩니다.
- 인스턴스가 더이상 사용되지 않는다면 ARC는 그 인스턴스가 차지하고 있는 메모리를 해지시키고 그 공간을 다른 용도로 사용할 수 있게 확보해둡니다.
- ARC는 최소 하나라고 그 인스턴스에 대한 참조가 있는 경우 그 인스턴스를 메모리에서 해지하지 않습니다.
❗️ 만약 아직 사용 중인 인스턴스를 메모리에서 해지했을 때 인스턴스의 프로퍼티에 접근한다면 앱은 아마 크래시가 발생하게됩니다.
사용 방법
ARC의 동작을 이해하기 위해 간단하게 사용해보도록 하겠습니다.
class Flower {
let name: String
init(name: String) {
self.name = name
print("init")
}
deinit {
print("deinit")
}
}
var reference1: Flower?
var reference2: Flower?
var reference3: Flower?
Flower
라는 클래스를 선언해주었고 그 아래 reference 변수 3개를 선언하였습니다. 클래스 인스턴스 생성에 참조를 하게 해주면
reference1 = Flower(name: "rose")
//print "init"
Print 문으로 인스턴스 생성이 되었다는 것을 알 수 있습니다.
reference2 = reference1
reference3 = reference1
reference 2, 3은 모두 처음에 reference1이 참조하는 Flower
인스턴스를 참조하게 됩니다. 이때 Flower
인스턴스에 대한 참조 횟수는 3이 됩니다
reference1 = nil
reference2 = nil
nil로 reference1, 2의 참조를 해지하게 됩니다. 이 시점에서 참조횟수는 얼마일까요? 아직 reference3의 참조가 남아있으니 1이 남습니다. 아까 최소 하나라도 인스턴스에 대한 참조가 있다면 메모리에서 해지할 수 없다고 했던 것처럼 지금 상태로는 Flower
인스턴스의 해지가 되지 않습니다.
reference3 = nil
이 코드를 마지막으로 더이상 Flower
인스턴스를 참조하는 것이 없기 때문에 메모리에서 해지됩니다
🥊 ARC vs GC
GC
먼저 GC는 런타임 시 프로그램이 동적으로 할당했던 메모리 영역 중에서 필요없게 된 영역을 해제합니다.
Q. 그렇다면 필요없게 된 영역을 어떻게 해제할까요?
A. Heap 내에서 객체의 수명을 관리하기 위해(오래된 객체를 판별하기 위해) young, old 구역으로 나뉘고 young은 그 안에서 Eden, Survivor로 나뉘게 됩니다
young 영역은 새롭게 생성한 객체의 대부분이 여기 위치하고 대부분의 객체가 금방 접근 불가능 상태가 되기 떄문에 많은 객체가 young 영역에서 생성되었다가 사라집니다
old 영역은 접근 불가능한 상태로 되지 않아 yound 영역에서 살아남은 객체가 여기로 복사됩니다
여기서 GC는 세 단계로 나뉘게 됩니다.
- Minor GC = young 영역만 뒤져서 판별
- Major GC = old 영역까지 뒤져서 판별
- Full GC = permanent 영역까지 뒤져서 판별
영역과 영역 사이를 오가고 여러 GC가 발생할 때마다 더이상 참조되지 않는 객체는 메모리에서 제거되게 됩니다
ARC와 GC의 차이
- 가장 큰 차이는 처리되는 시점이다 ARC, GC는 각각 컴파일 시, 런티임 중에 실행되는데 GC와 같이 런타임 중에 메모리를 검사하면 앱 퍼포먼스에 악영향을 줍니다
- GC는 런타임 외의 메모리 감시를 위한 추가자원이 필요해 한정적인 자원 환경에서 성능 저하가 발생할 수 있으나 ARC는 인스턴스 해제 시점을 컴파일 당시 예측 가능하여 시스템 자원을 추가할 필요가 없습니다.
🎯ARC vs MRC
MRC
Menual reference counting 의 약어로 obj-c를 사용할 때 참조를 수동으로 계산해야합니다.
alloc, new, cioy, mutalbeCopy, preserve 등 을 사용하여 obj-c에 대한 참조 를 수동으로 만들고 계산 해야합니다. 현재 ARC를 지원함으로써 MRC를 통해 수동으로 메모리 관리는 필요하지 않습니다.
MRC의 경우 개발자가 직접 카운팅을 해야하기 때문에 인스턴스의 RC에 접근할 수 있는 프로퍼티가 존재합니다. = retainCount
하지만 애플 공식 문서에서
retainCount의 경우… autorelease pool에 의해 release가 지연된 Count를 갖고있을 수 있어서 유용한 정보를 얻을 수 있는 방법이 매우 낮다 고함
ARC와 MRC의 차이
- 가장 큰 차이는 카운팅을 수동으로 하느냐 자동으로 하느냐입니다.