ARC
메모리 영역중 Heap 영역을 관리
Swift는 인스턴스, 클로저 등등 참조 타입을 자동으로 Heap에 할당
ARC는 클래스 인스턴스가 더 이상 필요하지 않을 때 메모리를 자동으로 해제함
Reference Count로 메모리를 관리 → 메모리 참조 횟수를 계산하여 참조 횟수가 0이 되면 더 이상 사용하지 않는 메모리라 판단하여 해제
모든 인스턴스는 자신의 RC값을 가지고 있으며 누가 가르키고 있느냐 없느냐를 숫자로 표현됨
Process
class Human {
var name: String?
var age: Int?
init(name: String?, age: Int?) {
self.name = name
self.age = age
}
}
let sodeul = Human(name: "Sodeul", age: 26)
지역 변수 jaebi는 Stack에 할당, Human 인스턴스는 Heap에 할당
sodeul은 일단 어디 클래스에 생성된 지역 변수라고 가정
인스턴스를 새로 생성할 때 해당 인스턴스에 대한 RC 증가
let clone = sodeul
인스턴스가 복사되지 않음으로 실제 메모리는 같은 Heap 영역의 인스턴스를 point
기존 인스턴스를 다른 변수에 대입할 때도 RC 값 증가
func makeClone(_ origin: Human) {
let clone = origin // ② Instance RC : 2
}
let sodeul = Human(name: "Sodeul", age: 26) // ① Instance RC : 1
makeClone(sodeul)
// ③ Instance RC : 1
참조 횟수 내려가는 경우 # 1
sodeul이 생성되는 순간 인스턴스의 RC +1
makeClone의 sodeul을 참조하는 clone변수가 생성되면서 인스턴스의 RC +1
인스턴스를 가르키던 변수가 메모리에서 해제되면서 RC -1
var sodeul: Human? = .init(name: "Sodeul", age: 26) // ① Instance RC : 1
var clone = sodeul // ② Instance RC : 2
clone = nil // ③ Instance RC : 1
sodeul = nil // ④ Instance RC : 0 (메모리 해제)
makeClone함수가 종료되어 메모리에서 해제됨
또는 clone = nil 로 메모리에서 해제
var sodeul: Human? = .init(name: "Sodeul", age: 26) // ① Sodeul Instance RC : 1
var clone: Human? = .init(name: "Sodeul2", age: 26) // ② Clone Instance RC : 1
sodeul = clone // ③ Clone Instance RC : 2, Sodeul Instance RC : 0 (메모리 해제)
2개의 인스턴스 - sodeul, clone 생성
sodeul = clone 로 값을 대입
참조 횟수 내려가는 경우 # 3
변수에 다른 값을 대입
sodeul의 RC는 -1, clone의 RC는 +1
sodeul이 가르키던 인스턴스 RC가 0이 되면서 ARC가 자동으로 메모리 해제
class Contacts {
var email: String?
var address: String?
init(email: String?, address: String?) {
self.email = email
self.address = address
}
deinit { print("Contacts Deinit)" } }
}
class Human {
var name: String?
var age: Int?
var contacts: Contacts? = .init(email: "o_o@naver", address: "Suwon")
init(name: String?, age: Int?) {
self.name = name
self.age = age
}
deinit { print("Human Deinit)" } }
}
let sodeul: Human? = .init(name: "Sodeul", age: 26)
sodeul = nil
Human 클래스 안에 contacts 클래스 인스턴스가 있음으로 두 인스턴스 각각의 RC 증가
sodeul에 nil을 할당한 순간 Human 인스턴스의 RC -1
Human의 RC가 0으로 되면서 메모리에서 해제 → contacts 프로퍼티도 메모리에서 해제 되면서 RC -1
Contacts 인스턴스도 RC가 0이 되며 메모리에서 해제
참조 횟수 내려가는 경우 # 4
프로퍼티의 경우 속해 있는 클래스 인스턴스가 메모리에서 해제
Human 클래스 안에 contacts 클래스 인스턴스가 있음으로 두 인스턴스 각각의 RC 증가
유의사항:
Human 인스턴스가 메모리에서 해제 되면서 property인 contacts가 가르키던 Contacts인스턴스의 메모리도 같이 해제 되는게 아님 → RC가 -1 감소할 뿐
따라서 RC가 0이 되었을때 인스턴스가 메모리에서 해제
Strong, Weak, Unowned
Strong
Weak
Unowned
설명
순환참조로 각각 RC +1이 되면서 cheolsu와 yeounghee를 nil로 대입시 메모리 해제가 되지 않고 heap에 남아 있음
순환 참조이지만 weak로 선언되어 RC값을 올리지 않음
인스턴스를 참조하는 도중에 인스턴스가 메모리에서 사라질 일이 없다고 확신 해야함
weak의 경우 `cheolsu?.girlfriend -> nil`
unowned의 경우 `cheolsu?.girlfriend -> error: signal SIGABRT` 발생
Reference Counting
O
X
X
사용 시점
강한 순환 참조가 발생할 경우
참조하는 인스턴스가 먼저 메모리에서 해제 될 가능성이 없을 시
특징
강한 순환 참조(Circular Reference)로 인해 Memory leak 발생할 수 있음
참조하던 인스턴스가 해제되면 자동으로 nil 할당
수명이 더 짧은 인스턴스를 가르키는 애를 weak참조로 선언
참조하는 인스턴스가 먼저 메모리에서 해제되면, 해제된 주소값을 게속 들고 있음 (에러 가능성)
unowned는 에러를 발생 시킬 위험이 있어 weak 권장
수명이 긴 인스턴스를 가르키는 애를 unowned참조로 선언
Reference
iOS) 메모리 관리 (1/3) - ARC(Automatic Reference Counting)
안녕하세요~~ 소들입니다 👀 오늘은 지난 시간 메모리 구조에 이어 Swift를 사용할 때 메모리 관리가 어떤 식으로 되는지에 대해 공부해볼 거예요 :) ARC 면접 단골 질문이라죠? 깔깔 iOS 개발자라
babbab2.tistory.com