ARC(Automatic Reference Counting)
Reference Type
의 인스턴스 메모리 관리를 자동으로 해주는 기능입니다.
Value Type
의 인스턴스는 ARC
가 관리하지 않습니다.
- 메모리 관리를 직접 하지 않아도
ARC
가 자동으로 메모리 관리를 처리합니다.
Reference Type
의 인스턴스를 참조할 때, 참조카운트가 증가하며, 이를 strong
참조라고 합니다.
- 참조카운트의 증가를 원하지 않는 경우
weak
또는 unowned
참조를 사용할 수 있습니다.
ARC 동작 방식
- 인스턴스 생성과 메모리 할당
class
의 새로운 인스턴스를 생성할 때 마다 ARC 는 해당 인스턴스에 대한 정보를 저장할 메모리 공간을 할당합니다.
- 이 공간에는 인스턴스의 타입 정보와 프로퍼티의 값이 저장됩니다.
- 참조 카운트 관리
- ARC는 사용중인 인스턴스가 메모리에서 해제되지 않도록, 몇개의 프로퍼티, 상수, 변수가 인스턴스를 참조하고 있는지 추적합니다.
- 참조 시작시: 카운팅 +1
- 참조 종료시: 카운팅 -1
- 최종적으로 참조카운트가 0이 되면 인스턴스는 메모리에서 해제됩니다.
- 메모리 해제
- 참조카운트가 0이 된 인스턴스는 더이상 필요하지 않기 때문에, ARC가 해당 인스턴스가 사용했던 메모리를 해제합니다.
- 만약 참조 카운트가 0이 되기전에 인스턴스가 해제되면, 이후 그 인스턴스에 접근할 경우 앱이 크래시가 발생할 수 있습니다.
ARC 동작 시기
- ARC는
컴파일타임
에 인스턴스의 참조 카운트를 증가 또는 감소시키는 코드를 자동으로 삽입합니다.
Memory Leak
메모리누수
- 사용이 끝난 인스턴스가 메모리에서 해제되지 않고 남아있는 현상입니다.
- 이렇게 메모리 공간이 불필요하게 사용되면 성능 저하가 발생할 수 있습니다.
강한순한참조(Strong Reference Cycle)
- iOS에서 자주 발생하는
Memory Leak
의 원인중 하나입니다.
class Person {
let name: String
init(name: String) { self.name = name}
var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized")}
}
Person
과 Apartment
는 서로를 참조하고 있기 때문에 순환 참조가 발생할 수 있습니다.
var john: Person?
var unit4A: Apartment?
john = Person(name: "John")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil
unit4A= nill

- Person instance와 Apartment instance의 RC가 1로 사용이 종료되었지만 메모리에서 해제되지 않음.
- 강한 참조로 서로를 참조한다고 하여 강한순한참조라고 합니다.
강한순한참조 해결방법
- 참조 카운트를 올리지 않으면 강한순한참조를 방지할 수 있습니다.
- 참조 카운트를 올리지 않기 위해서는
strong
이 아닌 weak
, unowned
를 사용하면 됩니다.
class Person {
let name: String
init(name: String) { self.name = name }
weak var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
class Apartment {
let unit: String
init(unit: String) { self.unit = unit }
weak var tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
var brody: Person?
var unit100A: Apartment?
brody = Person(name: "brody")
unit100A = Apartment(unit: "100평 아파트")
brody.apartment = unit100A
unit100A.tenant = brody
brody = nil
unit100A = nil
객체를 참조하는 방법 3가지
- strong
- 강한 참조
Dufault
값 입니다!
- 객체를 참조 시작하면 참조카운트가 1 올라감
- 객체 참조가 종료되면 참조카운트가 1 내려감
- weak
- 약한 참조
- 객체를 참조하면 참조카운트가 변하지 않음
- 객체 참조가 종료되도 참조카운트가 변하지 않음
- nil을 허용
- inowned
- 미소유 참조
- 객체를 참조하면 참조카운트가 변하지 않음
- 객체 참조가 종료되도 참조카운트가 변하지 않음
- nil이면 크래시 발생