-
Swift 메모리 관리: ARCios/Etc 2022. 3. 22. 15:06728x90
ARC(Automatic Reference Counting)
자동으로 참조 카운팅을 해주는 것 (+MRC(Manual Reference Counting): 수동으로 참조 카운팅을 하는 것)
// 일반적인 클래스 선언 class Person { let name: String init(name: String) { self.name = name } } //ARC 클래스 선언 class Person { let name: String init(name: String) { self.name = name } deinit { print("\(name)은 디이니셜됩니다.") } }
ARC는 어떻게 동작할까
강한 참조를 자동으로 카운트한다.
- 강한 참조는 프로퍼티, 상수 또는 변수에 클래스 인스턴스를 할당하는 것을 강한 참조라고 한다.
//강한 참조 class Person { ... } let John: Person? var John2: Person? John = Person(name: "John Appleseed")
- 인스턴스를 함수나 메서드에 인자로 전달하면 해당 블록이 실행되는 동안 참조 카운트가 증가하고 함수나 메서드가 종료되면 참조 카운트가 감소한다.
struct Car { func fixed(Fixer: Person){ print("\(Fixer)의 참조 카운트는 자동차를 고치는 동안 1 증가합니다.") print("\(Fixer)가 자동차를 고치는 중") print("\(Fixer)의 참조 카운트는 fixed 함수가 끝나면 1 감소합니다.") } } var John: Person? John = Person(name: "John Applessed") var hyundaiCar = Car() hyundaiCar.fixed(Fixer: John!)
- 함수나 메서드, 클로저 등 코드 블럭 내에서 생성한 인스턴스는 당연히 해당 코드 블럭이 끝나면 참조 카운트가 감소한다.
struct Car { func fixed(Fixer: Person) { print("\(Fixer.name)의 조수를 모집합니다.") let assistant = Person(name: "Steve Wozniak") print("\(Fixer.name)와 \(assistant.name)가 자동차를 고치는 중") print("\(Fixer.name)과 \(assistant.name)의 참조 카운트는 fixed 함수가 끝나면 1 감소합니다.") } }
- 강한 참조가 없다면 deinit 메서드가 실행된 후 해당 인스턴스는 자동으로 메모리에서 할당 해제된다.
- 강한 참조가 남아있다면 해당 인스턴스를 할당 해제하지 못한다.
예제
1.
Code RC reference1 = Person(name: "John") 1 reference2 = reference1 2 reference3 = reference2 3 reference1 = nil 2 reference2 = nil 1 reference3 = nil 0 2.
Code RC reference1 = Person(name: "John") 1 reference2 = Person(name: "John") 1 reference3 = Person(name: "John") 1 reference1 = nil 0 reference2 = nil 0 reference3 = nil 0 3.
Code RC reference1 = Person(name: "John") 1 reference2 = reference1 2 reference1 = nil 1 reference3 = reference1 1 reference4 = reference2 2 reference3 = nil 2 강한 참조로만 구성하면 발생하는 문제
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") } //MARK: 강한 참조 구현 //인스턴스 생성 var john: Perons? var number73: Apartment? //강한 참조 john = Person(name: "John") number73 = Apartment(unit: "4A") //각 클래스 내부에 있는 다른 인스턴스가 서로를 강한 참조 john!.apartment = number73 number73!.tenant = john //인스턴스는 끊어졌는데 내부의 apartment가 number73을 참조하고 있고 Person이 john을 참조하고 있어 메모리에서 할당이 해제되지 않음 john = nil number73 = nil
해결방법
약한 참조
- 참조하는 인스턴스가 메모리에서 해제될 수도 있다는 것을 예상해 인스턴스를 참조하더라도 참조 횟수를 늘리지 않는 참조
- 프로퍼티나 변수 앞에 weak 을 추가하여 사용 ( weak var tenant: Person?)
- 약한 참조는 항상 변수로 선언해야 한다. (상수로 선언하면 안된다.)
- 약한 참조는 항상 옵셔널로 선언해야 한다.
미소유 참조
- 참조하는 인스턴스가 항상 메모리에 존재할 것이라는 것을 예상해 인스턴스를 참조하더라도 참조 횟수를 늘리지 않는 참조
- 프로퍼티나 변수 앞에 unowned를 추가하여 사용 ( unowned var tenant: Person)
- 참조하는 인스턴스가 메모리에서 해제되더라도 자동으로 nil을 할당해주지 않음
- 메모리에서 해제된 인스턴스에 접근하려 하면 잘못된 메모리 접근으로 런타임 오류가 발생 -> 프로세스가 강제로 종료됨
참조
야곰의 스위프트 프로그래밍
iOS와 OS X의 메모리 관리와 멀티스레딩 기법 - OSXDEV 저
빅 너드 랜치의 스위프트 프로그래밍
Ojective-C 개발자를 위한 SWIFT 김근영 저
728x90'ios > Etc' 카테고리의 다른 글
@escaping (0) 2022.05.14 Concurrency & Threading (0) 2022.04.08 GoF Design Pattern (0) 2022.03.06 Cocoa란?(Feat. iOS, macOS) (0) 2022.03.05 Life Cycle (0) 2022.02.23