정상 증가 예
- 이미지 리스트 진입 시 캐시 워밍으로 메모리 증가
- 대형 JSON 파싱 중 임시 버퍼 증가
- 스크롤 중 prefetch로 일시적 객체 증가
중요한 건 "나중에 회수되는가"다.
메모리 그래프가 올라간다고 전부 누수는 아니다. "정상 증가"와 "해제되지 않는 누수"를 구분해야 정확한 대응이 가능하다.
2026-04-30
| 구분 | 의미 | 시간 경과 패턴 |
|---|---|---|
| 메모리 증가 | 작업량에 따라 일시적으로 메모리가 늘어나는 상태 | 작업 종료/압박 시 다시 내려갈 수 있음 |
| 메모리 누수 | 더 이상 필요 없는 객체가 참조 때문에 해제되지 않는 상태 | 반복할수록 계단식/지속 상승, 회복 안 됨 |
중요한 건 "나중에 회수되는가"다.
final class A {
var onDone: (() -> Void)?
}
final class B {
let a = A()
func bind() {
a.onDone = {
self.doWork() // self 강한 캡처
}
}
func doWork() {}
}final class B {
let a = A()
func bind() {
a.onDone = { [weak self] in
self?.doWork()
}
}
deinit {
a.onDone = nil
}
func doWork() {}
}final class FeedViewModel {
init() {
NotificationCenter.default.addObserver(
self,
selector: #selector(onRefresh),
name: .init("refresh_feed"),
object: nil
)
}
@objc private func onRefresh() { }
}final class FeedViewModel {
private var token: NSObjectProtocol?
init() {
token = NotificationCenter.default.addObserver(
forName: .init("refresh_feed"),
object: nil,
queue: .main
) { [weak self] _ in
self?.onRefresh()
}
}
private func onRefresh() { }
deinit {
if let token {
NotificationCenter.default.removeObserver(token)
}
}
}final class CountdownController {
private var timer: Timer?
func start() {
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
self.tick() // self 강한 캡처
}
}
private func tick() { }
}final class CountdownController {
private var timer: Timer?
func start() {
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
self?.tick()
}
}
private func tick() { }
deinit {
timer?.invalidate()
timer = nil
}
}
retain cycle이 생기는 이유와 끊는 방법
ARC가 객체 생명주기를 어떻게 관리하는지
대형 이미지가 메모리를 많이 쓰는 이유