메모리와 디스크 기본 개념
메모리
- 일반적으로 RAM 을 말하는 경우가 많다.
- 맥북에서도 몇 GB 짜리 RAM 을 사용하는지 볼 수 있다.
- RAM 은 휘발성 메모리이다. 즉, 데이터를 영구적으로 저장하지 않는다. 일시적인 저장에 사용한다.→ 앱도 결국 데이터 덩어리이기 때문에, 실행을 시키면 메모리에 올라간다.→ RAM 의 용량이 클 수록, 동시에 실행시킬 수 있는 앱의 총량이 높아진다고 생각할 수 있다.
- → 그렇기 때문에 메모리에 저장된 데이터는 앱이 메모리에서 내려올 때 같이 내려오게 되는 것.
- → 앱 실행중에 메모리에 저장된 데이터들은 앱을 종료하면 함께 삭제된다. (휘발된다)
- 디스크보다 속도가 빠르다. (CPU 가 디스크보다 메모리에 더 빨리 접근할 수 있다.)
- 디스크에 비해 용량이 작다. (보통 8GB, 16GB, 32GB)
- EEPROM 과 같은 비휘발성 메모리도 있다. 아이폰은 이곳에 장치의 일련번호 및 하드웨어 정보를 저장한다.
디스크
- 영구적인 데이터를 저장하는 곳. 비휘발성 장치.
- → 앱 실행중에 디스크에 저장된 데이터들은 앱을 종료해도 디스크에 남는다.
- 파일, 문서, 프로그램 등 상대적으로 용량이 큰 정보들을 담을 수 있다.
- 메모리에 비해 속도가 느리다.
- UserDefaults, CoreData 를 활용해서 디스크에 데이터를 저장할 수 있다.
Reference Counting

메모리를 할당 받은 객체를 인스턴스라고 부른다. 예를 들어 아래 코드에서는 myClass 가 인스턴스가 된다.
class MyClass {}
// 메모리를 할당받음. 인스턴스.
let myClass = MyClass()
인스턴스는 하나 이상의 참조자(소유자 = owner)가 있어야 메모리에 유지된다. 소유자가 없다면 그 즉시 메모리에서 제거 된다. 이 때 인스턴스를 참조하고 있는 소유자의 개수를 reference count 라고 한다.
reference count > 0 이면 메모리가 살아있고, reference count = 0 이면 메모리에서 삭제된다.
그렇기 때문에, 더 이상 사용하지 않을 인스턴스의 reference count 가 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 = 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 People {
let mbti = "ISTP"
init() {
print("클래스 생성")
}
deinit {
print("클래스 소멸")
}
}
// people RC = 1
var people: People? = People()
// 클로저 내부에서 people 캡쳐, RC 1증가. people RC -> 1 + 1 = 2
let printMBTI: () -> () = {[people] in
guard let people else { return }
print("people's MBTI = \(people.mbti)")
}
printMBTI()
// people RC -> 2 - 1 = 1
people = nil
위 코드를 보면 printMBTI 라는 클로저를 선언했고, 클로저 내부에서 클로저 외부의 값을 people 이라는 객체를 가져다 쓰고 싶으면 값을 캡처해야 한다. 이 때 [ ] 로 감싸면 값을 캡처링해서 클로저 내부에서 값을 사용할 수 있게된다.
클로저 내부에서 값을 캡처하면 RC가 1 증가한다. 그렇기 때문에 위 예시에서는 people 의 deinit 소멸자가 호출되지 않게된다.
위 코드를 개선하여 메모리 누수가 발생하지 않는 상황을 만드려면 아래 코드처럼 작성해야 발생하지 않는다.
class People {
let mbti = "ISTP"
init() {
print("클래스 생성")
}
deinit {
print("클래스 소멸")
}
}
// people RC = 1
var people: People? = People()
// weak 키워드로 약참조를 하여 RC가 증가하지 않음
let printMBTI: () -> () = {[weak people] in
guard let people else { return }
print("people's MBTI = \(people.mbti)")
}
printMBTI()
// people RC -> 1 - 1 = 0
people = nil
위 코드를 실행시키면 deinit 의 "클래스 소멸" 이 호출되는 것을 확인할 수 있다.
순환참조

순환 참조는 위 사진과 같이 A가 B를 참조하고, 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
모든 코드는 GitHub 에서 확인할 수 있다.
iOS-Proficiency-Week/ReferenceCount.playground at main · sh990920/iOS-Proficiency-Week
iOS 앱개발 숙련주차 블로그 정리 자료. Contribute to sh990920/iOS-Proficiency-Week development by creating an account on GitHub.
github.com
'swift' 카테고리의 다른 글
| Swift Delegate 패턴 (0) | 2024.07.09 |
|---|---|
| CoreData 와 UserDefaults (0) | 2024.07.09 |
| UIViewController 생명주기 (3) | 2024.07.09 |
| UISegmentedControl (0) | 2024.07.03 |
| UIScrollView (0) | 2024.06.21 |