안녕하세요 차니에요~~!
Swift에서는 앱의 메모리 사용을 관리하기 위해 ARC(Automatic Reference Counting)을 사용합니다.
오늘은 ARC에 대해 알아보도록 하겠습니다.
1. ARC(Automatic Reference Counting)
인스턴스의 참조 횟수를 기준으로 ARC가 알아서 더이상 사용하지 않는 인스턴스를 메모리에서 해지합니다.
참조 횟수는 클래스 타입의 인스턴스에만 적용되고 값 타입인 구조체 열거형 등에는 적용되지 않습니다.
개발 용어는 대부분 한눈에 알수 있을 정도로 네이밍 된 경우가 많습니다.
하나 하나 뜯어보면..
- Automatic - 자동적인
- Reference - 참조
- Counting - 계산
이걸 그럴싸하게 조합을 해보면 "자동 참조 카운팅(계산)" 정도로 해석할 수 있습니다.
네, Swift에서 자동으로 메모리를 관리해주는 고마운 녀석입니다.
ARC는 WWDC 2011에 나온 개념입니다.
그러면.. 그 이전에는 메모리 관리를 어떻게 했을까요?
MRC에 대해 더 알아보겠습니다.
1-1. MRC(Manual Reference Counting)
MRC는 ARC 이전에 Apple에서 메모리를 관리하던 방식입니다.
마찬가지로 뜯어보면..
- Manual - 수동의
- Reference - 참조
- Counting - 계산
또 조합을 해보면 "수동 참조 카운팅(계산)" 정도가 되죠.
메모리 관리를 수동으로 한다면.. 귀찮고 번거로운 작업이 들어가기 때문에 ARC는 고마운 녀석이라고 했던 겁니다!
코드로 살짝 맛만 본다면
- (void)mrcExam {
NSDictionary *dic = nil; // RC == 0
dic = [[NSDictionary alloc] init]; // RC == 1
[dic release]; // RC == 0
}
처음 dic 변수는 nil 값을 가지고 있기 때문에 RC(Reference Counting)가 0입니다.
다음엔 alloc을 통해 메모리 주소값을 할당해주고 init을 통해 RC가 1이되었습니다.
마지막으로 release를 호출함으로써 RC가 0이 되고 메모리가 해제됩니다.
코드적으로 이해할 필요는 없고 retain, init(RC 증가), release(RC 감소) 등..
개발자가 수동으로 참조 카운팅을 코드로 짜 넣는 방식이라는 것만 알고 넘어가시면 됩니다!
그럼 Obj-C에서는 MRC만 사용해야 하나?
그건 아닙니다
프로젝트의 Build Settings에서 Objective-C Automatic Reference Counting을 YES로 설정해주면 사용 가능하고
Swift5 이상부터는 Default로 들어가기 때문에 따로 설정이 필요없습니다.
2. GC(Garbage Collector) VS ARC
자바에서는 ARC와 동일한 기능을 하는 가비지 컬렉터(GC)라는 개념이 있습니다.
같은 기능을 하지만 동작 방식이 다른 점이 있어요.
- GC : 프로그램 실행 중(Run Time)에 동적으로 감시하며 메모리 관리
- ARC : 빌드 시점(Complie Time)에 자동으로 RC를 감소시키는 코드를 삽입하여 메모리 관리
3. ARC의 사용
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
ARC가 어떻게 동작되는지 보기 위해 예제 코드를 통해 알아보도록 하겠습니다.
해당 예제는 애플 공식 가이드를 참고하여 작성하였습니다.
var reference1: Person?
var reference2: Person?
var reference3: Person?
Person 객체의 nil 인스턴스를 생성합니다.
이때 당연히RC는 0입니다.
reference1 = Person(name: "John Appleseed") // RC == 1
// Prints "John Appleseed is being initialized"
referenc1에 Person 인스턴스를 생성합니다.
그러면 "John Appleseed is being initialized" 가 출력되고 RC는 1로 증가합니다.
reference2 = reference1 // RC == 2
reference3 = reference1 // RC == 3
나머지 두 변수에 reference1 인스턴스를 주입합니다.
reference2, 3에서 reference1을 참조하므로 RC는 2가 증가되어 3이 됩니다.
reference1 = nil // RC == 2
reference2 = nil // RC == 1
reference1과 reference2를 다시 nil로 초기화 하면
아직 reference3에서 참조하고 있기 때문에 RC는 1이되어 Person 인스턴스는 해지되지 않습니다.
reference3 = nil // RC == 0
// Prints "John Appleseed is being deinitialized"
마지막 참조인 reference3를 nil로 초기화하면 RC가 0이 되므로 메모리가 해지되며 deinit에서 찍은 프린트 구문이 출력됩니다.