강한 순환 참조 어떻게 확인할까?(LLDB, View Memory Graph Hierarchy, Memory Leak)
2023. 2. 10. 23:34ㆍIOS
반응형
이것이 정답은 아니겠지만 활용방안도 무궁무진하고, 좋은 기능인것 같습니다
강한 순환 참조 문제 코드
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") }
}
- 해당 코드는 ARC 공식문서에 있는 강한 순환 참조가 발생하는 코드입니다
class ViewController: UIViewController {
var john: Person?
var unit4A: Apartment?
override func viewDidLoad() {
super.viewDidLoad()
john = Person(name: "John")
unit4A = Apartment(unit: "Xi")
john?.apartment = unit4A
unit4A?.tenant = john
}
@IBAction func didTapButton(_ sender: UIButton) {
john = Person(name: "ABC")
unit4A = Apartment(unit: "ABC")
john?.apartment = unit4A
unit4A?.tenant = john
}
}
- 해당
ViewController
는 버튼을 눌렀을 경우 새로운Person
,Apartment
인스턴스를 생성하여 각각의 변수에 할당해주는 과정을 반복한다 - 하지만 위 사진처럼 강한 순환 참조가 발생하므로 해당 클로저는 메모리에서 해제되지 않는다
- 똑똑한 사람이라면 이 코드를 보고 곧바로 강한 순환 참조문제가 발생하게 된다는 것을 알아차리겠지만 나는 아마 알아차리지 못할 것이다
Memory Leak 발생 확인
- 좌측 상단의 바에서 빨간색 사각형으로 표시된 부분을 클릭 할 경우 현재 동작하고 있는 앱을 여러 형태로 볼 수 있다.
- 우리는 여기서, View Memory Graph Hierarchy를 통해 해당 메모리의 상관관계와 타입에 남아있는 메모리를 볼 수 있다.
- 버튼을 누르면
Person
,Apartment
인스턴스가 지속적으로 생성됨으로Apartment
,Person
에 관한 타입에 메모리가 남아있는게 보이고 해당 메모리가 낭비되고 있다는 표시가 뜬다. - 이것으로 우리는 메모리 누수가 발생한다는 것은 확인할 수 있다.
- 그러나, 강한순환참조를 염두에 두고 이를 본다면 문제를 빠르게 찾아낼 수도 있겠지만 이것이 과연 강한순환참조의 문제로인한 누수인지 그 외의 문제인지 확인할 방법이 필요하다고 생각한다.
- 타입들의 아래 부분은 타입 인스턴스의 주소를 나타내는데 이를 클릭하면 구조를 볼 수 있다.
- 해당 구조를 보면
ViewController
에 많은 것이 연결되어 있는 것을 볼수 있지만 그 중에서 우리가 작성한 타입 중 하나인Apartment
를 볼 수 있다. - 그러나
Person
에 관한 인스턴스가 보이지 않아서 현재ViewController
가 가지고 있는Person
을 보기 위해서 이전 화면에서 메모리 누수가 발생하지 않는 주소 값을 클릭하였다.
- 이 경우 우리는
ViewController
에 연결되어있는Person
을 볼 수 있고 해당Person
은Apartment
를 가지고 있다는 것을 확인할 수 있다.
- 우측 상단에 보여지는 화살표를 누를 경우 해당
Apartment
에 연결되어있는 부분을 볼 수 있다.
- 위 두 사진을 보면 알 수 있듯이 해당 타입들은 지속적으로 서로를 참조하는 모습을 보여주며 우측 상단 화살표를 계속 누를 경우 끝도없이 나아가는 모습을 볼 수 있다.
- 이를 통해 우리는
Apartment
와Person
이 지속적으로 서로 참조하는 구조와 이전 메모리 누수를 통해 우리는 이 두가지 타입이 강한순환참조로 인해 메모리 누수가 발생한다는 것을 알 수 있다.
강한순환참조 해결
class Person {
let name: String
init(name: String) { self.name = name }
weak var apartment: Apartment?
deinit { print("\(name) is being deinitialized") }
}
- 기존 코드에서
Person
타입이 참조하는apartment
변수를weak
를 선언함으로 강한순환참조 문제를 해결하였다. - 위 진행방법을 토대로 메모리 누수가 되는지?, 구조는 어떻게 되는지? 한번 알아보자
- 버튼을 여러번 눌렀음에도 불구하고
Apartment
와Person
이 우리가 원하던대로 하나의 인스턴스 주소만 가지고 있다는것을 확인할 수 있다. - 여기서
Apartment
인스턴스를 클릭해보자
- 해당
Apartment
는 약한참조로 구현하지 않았으므로 정상적으로Person
을 참조하는 것처럼 보여지지만SwiftWeakRefStorage
를 통해 약한참조가 되어진다는 것을 확인할 수 있다. - 이번에는
Person
의 인스턴스를 클릭해보자
Person
은Apartment
와 조금 다른 구조를 가지고 있으며,ViewController
에서 바로 화살표가 뻗는것이 아닌malloc<64>
즉 메모리에 할당되는 것과 함꼐 출력되며Person
은SwiftWeakRefStorage
를 참조하고 있다.SwiftWeakRefStorage
를 클릭하여도 더 이상 늘어나지 않는다
다만 이 방법도 정답은 아니다 unowned 키워드를 사용할 경우 구조를 봤을 때 지속적으로 늘어나기 때문에 메모리 누수를 확인하면서 해당 구조를 확인하는 방법 두가지를 적절하게 섞어야할 것 같다
추가로 구조내에서 해당 타입을 클릭할 경우 참조카운트를 확인할 수 있는데 unowned를 사용할 경우 구조가 끝 없이 늘어나는대신에 참조카운팅이 0이므로 이를 토대로도 확인을 하여 강한순환참조문제를 해결해야할 것 같다.
참고자료
반응형
'IOS' 카테고리의 다른 글
TableView Section 글자가 대문자로 변해요~ (0) | 2023.02.25 |
---|---|
Json Decoding 어떤 문제로 실패한걸까?? (0) | 2023.02.25 |
NotificationCenter addObserver의 object활용 (0) | 2023.02.13 |
NotificationCenter 간단 정리 (0) | 2023.01.23 |
Delegate를 이용하여 뷰 컨트롤러간의 데이터 전달(양방향) (0) | 2023.01.13 |