
안녕하세요. 오늘은 Instruments를 활용하는 법을 익히기 위해서
의도적으로 메모리 릭을 발생시키고 Instruments로 확인하는 과정을 해보았습니다.
그런데 Instruments에서 감지가 안 되는 문제가 발생했습니다.
Instruments를 잘 사용하는 개발자가 되고 싶은데 가장 허들이 높은 것 같습니다. 😭
class ClassA {
var x: ClassB?
}
class ClassB {
var x: ClassA?
deinit { print("메모리 해제") }
}
@objc func buttonTapped() {
let classA = ClassA()
let classB = ClassB()
classA.x = classB // 순환 참조 발생
classB.x = classA
}
문제:
deinit이 호출되지 않음 (메모리 릭 확실)왜 감지가 안 되나?
iOS는 성능을 위해 메모리 할당 추적을 기본적으로 꺼놓는다고 합니다. 이게 꺼져있으면 Instruments가 어떤 메모리가 누수됐는지 알 수가 없습니다.
Malloc이란? C의 메모리 할당 함수. Swift에서 객체 생성 시 내부적으로 malloc()을 호출합니다.
설정 방법:
1. Product > Scheme > Edit Scheme (⌘<)
2. Run → Diagnostics 탭
3. ✅ Malloc Stack Logging 체크
결과: Leaks가 감지되기 시작했습니다! 하지만 Stack Trace는 여전히 비어있습니다.
왜 Stack Trace가 비어있나?
컴파일된 바이너리는 메모리 주소만 가지고 있습니다. 함수 이름, 파일명, 줄 번호 같은 심볼 정보는 별도 파일(dSYM)에 저장됩니다.
0x1a2b3c4d8 ← 이게 뭔지 알 수 없음
설정 방법:
1. 프로젝트 선택 → Build Settings
2. 검색: Debug Information Format
3. Debug/Release 모두 DWARF with dSYM File로 설정
이게 하는 일:
메모리 주소 → dSYM 파일 → ViewController.swift:47
함정: Instruments는 Recording 중에는 실시간 감지만 하고, 중지 후에 상세 분석을 시작합니다.

Recording이 진행 중일 때는 Stack Trace가 비어있습니다.

중지를 하니 Stack Trace의 내용이 추가되었습니다!
올바른 절차:
1. Profile 실행 (⌘I)
2. Leaks 템플릿 선택
3. 앱에서 버튼 여러 번 클릭
4. ⏹️ Recording 중지 ← 이때 Stack Trace 생성!
5. Leaks 선택 → Call Tree/Stack Trace 확인

Call Tree에서 내가 작성한 코드만 확인하고 싶다면, 시스템 라이브러리 호출을 필터링해야 합니다.

아래 Call Tree 설정에서 다음을 선택:
결과: 관련된 내용만 남게 되어, 어디서 어떤 함수 호출로 메모리 릭이 생겼는지 명확하게 알 수 있습니다!
메모리 릭 발생 → ❌ Leaks 감지 안 됨
↓
1. Malloc Stack Logging ON
↓
✅ Leaks 감지! (Stack Trace 없음)
↓
2. DWARF with dSYM 설정
↓
3. Recording 중지
↓
✅ Stack Trace 생성됨!
↓
4. Call Tree 필터링
↓
✅ 내 코드만 깔끔하게 표시!
Stack Trace:
#0 swift_allocObject
#1 ClassA.__allocating_init() at ViewController.swift:10
#2 ViewController.buttonTapped() at ViewController.swift:47
#3 @objc ViewController.buttonTapped()
이제 정확히 ViewController.swift 47번째 줄에서 메모리 릭이 발생했음을 알 수 있습니다!
Instruments로 메모리 릭 디버깅하려면 4가지 단계가 모두 필요합니다:
가장 많이 놓치는 것: