메모리와 디스크 기본 개념
메모리와 디스크는 모두 컴퓨터나 스마트폰에서 데이터의 저장 및 처리를 담당하지만 목적과 특성이 다르다.
▪️ 메모리
- 일반적으로 RAM을 말하는 경우가 많다.
- 맥북에서도 몇 GB 짜리 RAM을 사용하는지 볼 수 있다.
- RAM 은 휘발성 메모리이다. 즉, 데이터를 영구적으로 저장하지 않는다. 일시적인 저장에 사용한다.→ 앱도 결국 데이터 덩어리이기 때문에, 실행을 시키면 메모리에 올라간다.→ RAM의 용량이 클수록, 동시에 실행시킬 수 있는 앱의 총량이 높아진다고 생각할 수 있다.
- → 그렇기 때문에 메모리에 저장된 데이터는 앱이 메모리에서 내려올 때 같이 내려오게 되는 것.
- → 앱 실행중에 메모리에 저장된 데이터들은 앱을 종료하면 함께 삭제된다. (휘발된다)
- 디스크보다 속도가 빠르다. (CPU 가 디스크보다 메모리에 더 빨리 접근할 수 있다.)
- 디스크에 비해 용량이 작다. (보통 8GB, 16GB, 32GB)
- EEPROM과 같은 비휘발성 메모리도 있다. 아이폰은 이곳에 장치의 일련번호 및 하드웨어 정보를 저장한다.
▪️ 디스크
- 영구적인 데이터를 저장하는 곳. 비휘발성 장치.
- → 앱 실행중에 디스크에 저장된 데이터들은 앱을 종료해도 디스크에 남는다.
- 파일, 문서, 프로그램 등 상대적으로 용량이 큰 정보들을 담을 수 있다.
- 메모리에 비해 속도가 느리다.
- UserDefaults, CoreData를 활용해서 디스크에 데이터를 저장할 수 있다.
Reference Counting
Swift의 메모리 관리 시스템의 핵심이 되는 개념인 Reference Counting(RC)에 대해 공부합니다.
메모리를 할당 받은 객체를 인스턴스라고 합니다.
예를 들어 아래 코드에서 myClass는 인스턴스가 된 것이죠.
class MyClass {}
// 메모리를 할당받음. 인스턴스.
let myClass = MyClass()
인스턴스는 하나 이상의 참조자(소유자=owner) 가 있어야 메모리에 유지가 됩니다. 소유자가 없다면 즉시 메모리에서 제거가 됩니다. 이때 인스턴스를 참조하고 있는 소유자의 개수를 reference count 라고 합니다.
reference count > 0 이면 메모리에 살아있고, reference count = 0 이면 메모리에서 삭제됩니다.
그렇기 때문에, 더 이상 사용하지 않을 인스턴스의 reference coutn 가 0보다 크지 않도록 주의를 해야 합니다.
class MyClass {
init() {
print("MyClass 생성")
}
deinit {
print("MyClass 소멸")
}
}
// RC = 1
var myClass: MyClass? = MyClass()
// RC = 2
var myClass2 = myClass
// RC = 2-1 = 1
myClass = nil
// RC = 1-1 = 0
myClass2 = nil
ARC와 MRC
🧑🏻💻 ARC와 MRC의 개념을 공부해봅시다.
- ARC = Automatic Reference Counting
- MRC = Manual Reference Counting
- ARC
- ARC는 Swift 의 메모리 관리 시스템. Java 에 GC 가 있다면 Swift 에는 ARC 가 있음.
- Reference Count 를 자동으로 계산. (Automatic)
- 객체가 생성될 때 RC 가 1 로 설정
- 객체가 다른 변수나 속성에 할당되어 참조될때마다 RC 가 1 씩 증가
- 객체에 대한 참조가 해제될때마다 RC 가 감소
- RC 0 이 되면 더 이상 사용되지 않는 것으로 간주되어 메모리에서 해제.
- MRC
- MRC 는 Objective-C 에서 사용하는 메모리 관리 시스템.
- Reference Count 를 개발자가 코드로 직접 계산. (Manual)
- 객체가 생성될때 개발자가 명시적으로 메모리 할당
- 객체를 다른 변수나 속성에 할당되어 참조될때마다 개발자가 명시적으로 RC 증가
- 객체에 대한 참조가 해제될때마다 개발자가 명시적으로 RC 감소
- RC 가 0 이되면 개발자가 명시적으로 메모리에서 해제.
🙋🏻♂️ 그렇다면 ARC는 자동으로 RC 카운트를 해서 메모리 관리를 해주는 좋은 시스템이니, 개발자는 메모리 관리에 대해 신경 쓰지 않아도 되나요?
→ 그렇지 않습니다. ARC로 잡아내지 못하는 메모리 누수 상황이 발생할 수 있기 때문에, 개발자는 메모리 관리 방법을 반드시 알아야 합니다.
약참조와 강참조
🧑🏻💻 약참조와 강참조의 개념에 대해 공부해봅시다.
- 약참조
- Reference Count를 증가시키지 않으면서 참조하는 것.
- weak 키워드를 붙여서 약참조를 할 수 있다.
- 강참조
- Reference Count 를 증가시키면서 참조하는 것.
- 일반적인 참조 방식을 말한다.
클로저의 캡처링 개념
🧑🏻💻 Swift의 클로저 안에서 값을 사용하는 방법 중에는 캡처링 이 있습니다.
class Adam {
let mbti = "ENTJ"
init() {
print("클래스 생성")
}
deinit {
print("클래스 소멸")
}
}
// adam rc = 1
var adam: Adam? = Adam()
// 클로저 내부에서 adam 캡처. rc 1 증가. adam rc = 2
let printMbti: () -> () = { [adam] in
guard let adam else { return }
print("adam's mbti = \(adam.mbti)")
}
printMbti()
// adam rc = 2-1 = 1
adam = nil
printMbti라는 클로저를 선언했고, 클로저 내부에서 클로저 외부의 adam이라는 객체를 가져다 쓰고 싶으면 값을 캡처해야 합니다.
이때 [ ]로 감싸면 값을 캡처링해서 클로저 내부에서 사용할 수 있게 됩니다.
🌟 클로저 내부에서 클래스의 값을 캡처하면, Reference Count 가 증가합니다.
위 예시를 따라 해보면 adam의 deinit 소멸자가 호출되지 않습니다. 클로저에서 값을 캡처해 rc 가 증가했기 때문입니다.
위 코드를 개선해서, 메모리 누수가 발생하지 않는 상황을 만들려면 다음과 같이 코드를 작성해야 합니다.
class Adam {
let mbti = "ENTJ"
init() {
print("클래스 생성")
}
deinit {
print("클래스 소멸")
}
}
// adam rc = 1
var adam: Adam? = Adam()
// 클로저 내부에서 adam 캡처.
// weak 참조 했으므로 rc 가 증가하지 않음. adam rc = 1
let printMbti: () -> () = { [weak adam] in
guard let adam else { return }
print("adam's mbti = \(adam.mbti)")
}
printMbti()
// adam rc = 1-1 = 0
adam = nil
위 코드를 따라서 실행해 보면, 메모리가 해제되고 deinit ”클래스 소멸” 이 호출되는 것을 확인할 수 있습니다.
순환 참조 (Circular Reference)
🧑🏻💻 순환 참조
A 가 B를 참조하고 (A→B),
B 가 A를 참조해서 (B→A), 서로가 서로를 참조하는 상황을 순환 참조라고 합니다.
일반적으로 순환 참조는 메모리 누수를 발생시키는 대표적인 사례입니다.
아래 예시를 보고 순환 참조 개념을 이해해 봅시다.
class Person {
var pet: Dog?
init() {
print("Person 클래스 생성")
}
deinit {
print("Person 클래스 소멸")
}
}
class Dog {
var owner: Person?
init() {
print("Dog 클래스 생성")
}
deinit {
print("Dog 클래스 소멸")
}
}
// person rc = 1
var person: Person? = Person()
// dog rc = 1
var dog: Dog? = Dog()
// dog rc = 2
person?.pet = dog
// person rc = 2
dog?.owner = person
// person rc = 1
person = nil
// dog rc = 1
dog = nil
→ 따라서, 개발자는 개발할 때 순환참조가 발생하는 상황이 아닌지 점검할 줄 알아야 합니다.
'스파르타 코딩 클럽 - iOS 스타터 6기 > 본 캠프' 카테고리의 다른 글
32. 스파르타 코딩 클럽 - 네트워크 통신 이해 (1) | 2025.04.15 |
---|---|
31. 스파르타 코딩 클럽 - CoreData와 UserDefaults (0) | 2025.04.15 |
29. 스파르타 코딩 클럽 - ViewController 생명주기 (1) | 2025.04.14 |
28. 스파르타 코딩 클럽 - 팀 프로젝트 4, 5일차 [마무리] (1) | 2025.04.11 |
27. 스파르타 코딩 클럽 - 팀 프로젝트 3일차 (0) | 2025.04.09 |