일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- IOS
- 스터디
- 조건문
- xcode
- WidgetTree
- 알고리즘
- CS193p
- process
- colorofdays
- UserDefault
- flutter #state # stateful #stateless
- ImageSlider
- Masil
- flutter
- 프로그래머스
- collectionView
- MVVM
- SwiftUI
- 프로젝트회고
- UIKit
- 코딩테스트
- 백준
- GIT
- 새싹후기
- 청년취업사관학교후기
- 스위프트
- Swift
- 오늘의 색상
- stanford
- xml
- Today
- Total
개발을 시작하는 이야기
ARC(Automatic Reference Counting) 본문
ARC(Automatic Reference Counting)
iOS는 앱의 메모리 사용을 추적, 관리하기 위해 ARC 기능을 사용한다.
ARC는 Automatic Reference Counting의 줄임말로 참조 메모리 관리를 자동으로 해주는 기능을 뜻한다.
인스턴스가 참조되거나 참조 해제될 때 횟수를 카운팅 하고, 횟수가 0이 되면 인스턴스를 메모리에서 해제하는 방식
How ARC Works
클래스가 새로운 인스턴스를 생성할 때, ARC는 인스턴스에 대한 정보를 저장할 메모리 청크를 할당한다.
할당한 메모리 청크에는 인스턴스의 타입에 대한 정보, 인스턴스와 관련된 프로퍼티 값 등을 저장해둔다.
더 이상 인스턴스가 필요하지 않게 되면 자동으로 메모리에서 비우는 방식으로 메모리를 관리한다.
ARC in Action
예시를 통해 살펴보자면
class Person {
let name: String
init(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit{
print("\(name) is being deinitialized")
}
}
위 코드는 name이라는 상수 프로퍼티를 가지고 있는 person 클래스를 선언한 것이다.
person 클래스는 인스턴스의 name 프로퍼티를 set 하고, 초기화되었음을 알리는 initializer와 클래스 인스턴스가 메모리에서 해제될 때 메시지를 출력하는 deinitializer가 있다.
var reference1: String?
var reference2: String?
var reference3: String?
reference1 = Person(name: "John Appleseed")
//Prints "John Appleseed is being initialized"
위 코드에서는 Person 클래스 인스턴스를 설정하기 위한 Person? 타입의 변수 3개를 선언한 후 reference1에 새로운 Person 클래스 인스턴스를 할당한다.
이때 reference1 변수와 Person 클래스의 인스턴스가 강한 참조로 연결된다.
적어도 하나의 강한 참조로 연결되어 있기 때문에 ARC는 Person 클래스가 메모리에 유지되고 할당 해제되지 않도록 한다.
reference2 = reference1
reference3 = reference1
나머지 두개의 변수에 위에서 만든 Person 인스턴스를 할당했다.
이렇게 되면 하나의 Person 클래스 인스턴스에 총 3개의 강한 참조가 연결된다.
reference1 = nil
reference2 = nil
두개의 변수에 nil을 할당하여 강한 참조 중 두 개(원래 참조 포함)를 중단하면 하나의 강한 참조만 남게 된다.
ARC는 Person의 세번째이자 마지막 강한 참조가 깨질 때까지 인스턴스를 할당 해제하지 않는다.
reference3 = nil
//Prints "John Appleseed is being deinitialized"
이렇게 하나 남은 강한 참조까지 끌어줘야 Person 클래스 인스턴스가 메모리에서 할당 해제된다.
Strong Reference Cycles Between Class Instances
위의 예시에서 ARC는 생성한 새 인스턴스에 대한 참조 수를 추적하고 Person 클래스가 더 이상 필요하지 않을 때 해당 인스턴스를 할당 해제할 수 있다.
그러나 클래스의 인스턴스가 강한 참조가 0인 지점에 도달하지 않는 코드를 작성할 수 있다. 이는 두 개의 클래스 인스턴스가 서로 강한 참조를 유지하여 각 인스턴스가 다른 인스턴스를 계속 활성 상태로 유지하는 경우 발생할 수 있는데 이를 강한 순환 참조라고 한다.
강한 참조 대신 weak reference와 unowned reference를 사용하여 강한 순환 참조를 해결한다. 그러나 강한 순환 참조가 어떻게 발생하는지 이해하는 것이 좋다.
다음은 강한 순환 참조가 생성될 수 있는 방법의 예시이다. 이 예는 아파트 블록과 주거자를 모델링하는 두 개의 클래스를 정의한다.
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 클래스는 각각 String 타입의 상수를 하나씩 가지고 있고, Person 클래스는 Apartment? 타입의 변수를 하나, Apartment 클래스는 Person? 타입의 변수 하나를 가지고 있다. 각각의 클래스는 deinit 함수를 갖고 있다.
var johon: Person?
var unit4A: Apartment?
각각 john과 unit4A 변수는 Person과 Apartment의 인스턴스로 설정되는데. 두 변수는 모두 선택 사항이기 때문에 초기값은 nil이다.
john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")
john과 unit4A 변수에 각각 Person과 Apartment인스턴스를 할당해준다.
이렇게 되면 john 변수는 person 인스턴스에 강한 참조를 갖고, unit4A 변수는 Apartment 인스턴스에 강한 참조를 갖게 된다.
이때, john의 apartment 프로퍼티에 Apartment의 인스턴스인 unit4A를 넣어주고, unit4A의 tennant 프로퍼티에 Person의 인스턴스인 john을 넣어주게 되면 다음과 같은 참조 관계를 갖게 된다.
이제 Person 인스턴스는 Apartment 인스턴스에 강한 참조를 갖게 되고, Apartment 인스턴스는 Person 인스턴스에 강한 참조를 갖게 됨으로써 john과 unit4A는 강한 순환 참조로 연결된다.
john = nil
unit4A = nil
따라서 이제는 각각의 참조를 끊는다고 해도 참조 개수가 0이 되지 않기 때문에 ARC에서 인스턴스를 할당 해제하지 않게 된다.
즉, 앱에서 메모리 누수를 일으키게 된다.
이제 Person과 Apartment 인스턴스 간의 강한 순환 참조는 유지되며 끊을 수 없다.
이러한 강한 순환 참조를 해결하기 위한 방법은 다음에 이어서
참고 : https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html
'개발 이야기 > Swift' 카테고리의 다른 글
앱 시닝(app thinning) (0) | 2022.03.20 |
---|---|
weak, unowned (0) | 2022.03.19 |
ViewController (0) | 2022.03.17 |
앱의 콘텐츠나 데이터 자체를 저장/보관하는 객체들 (0) | 2022.03.16 |
시뮬레이터의 차이점 (0) | 2022.03.15 |