**Garbage Collection (GC)**은 프로그램이 더 이상 사용하지 않는 메모리(객체)를 자동으로 해제하는 메모리 관리 기법입니다. GC는 주로 고급 언어(Java, Python 등)에서 제공되며, 프로그래머가 메모리를 직접 해제하지 않아도 되도록 하여 메모리 누수(Memory Leak)와 같은 문제를 줄여줍니다.
왜 필요할까?
컴퓨터에서 여러 프로그램을 사용하다 보면, 사용하다가 닫거나 더 이상 쓰지 않는 데이터들이 있습니다. 이런 데이터를 정리하지 않으면 컴퓨터가 느려지고, 멈출 수도 있습니다. 그래서 컴퓨터가 스스로 필요 없는 데이터를 찾아서 정리합니다.
Garbage Collection의 작동 방식
GC는 프로그램이 사용하지 않는 객체를 탐지하고, 이를 메모리에서 제거하여 다른 객체가 사용할 수 있도록 메모리를 회수합니다. 대표적인 방식은 다음과 같습니다:
- Reference Counting (참조 카운팅):
- 각 객체가 몇 번 참조되고 있는지 추적하는 방식입니다. 참조 횟수가 0이 되면 해당 객체는 더 이상 사용되지 않으므로 해제됩니다.
- 단점: 순환 참조(서로가 서로를 참조하는 객체들)가 발생하면 메모리가 해제되지 않는 문제가 있습니다.
- Mark-and-Sweep (마크 앤 스윕):
- 프로그램이 접근할 수 있는 객체(루트 객체)에서부터 연결된 모든 객체를 마킹하고, 마킹되지 않은 객체를 스윕(제거)하는 방식입니다.
- 메모리의 전체 상태를 주기적으로 검사하여 불필요한 객체를 제거하므로 순환 참조 문제를 해결할 수 있습니다.
- Generational Garbage Collection (세대별 GC):
- 객체를 생성된 시기에 따라 구분하고, 오래된 객체는 회수가 적게, 새로 생성된 객체는 회수가 잦게 이루어지도록 하여 효율성을 높이는 방식입니다.
- 대부분의 최신 GC에서 사용하는 방식이며, Java의 HotSpot VM과 Python에서 사용됩니다.
Garbage Collection의 장점과 단점
- 장점:
- 자동으로 메모리를 관리해주므로 프로그래머가 직접 메모리를 해제할 필요가 없어, 메모리 누수와 버그 발생 가능성을 줄여줍니다.
- 코드가 간결해지고, 메모리 관리 오류를 줄일 수 있습니다.
- 단점:
- GC가 동작할 때 프로그램의 성능이 일시적으로 저하될 수 있습니다. 이를 "Stop-the-World" 현상이라고 하며, GC가 메모리를 회수하기 위해 프로그램의 실행을 멈추는 시간이 발생하기 때문입니다.
- 다소 예측 불가능한 방식으로 메모리가 해제되므로, 실시간 처리가 중요한 프로그램에서는 문제가 될 수 있습니다.
스위프트에서는 어떻게 쓰이나?
Swift에서는 우리가 더 이상 필요 없는 메모리를 자동으로 정리해주는 기능이 내장되어 있습니다. Swift는 **Automatic Reference Counting (ARC)**라는 방식을 통해 가비지 컬렉션과 비슷한 기능을 수행합니다. Swift는 ARC를 통해 객체의 사용이 끝나면 자동으로 메모리를 해제하는데, 이것이 우리가 흔히 말하는 가비지 컬렉션과 같은 역할을 합니다.
ARC(Automatic Reference Counting)의 기본 원리
ARC는 객체(인스턴스)가 사용되고 있는지 추적해서 더 이상 사용하지 않는 객체는 메모리에서 해제해요. **이 추적은 객체를 참조하는 횟수(Reference Count)**를 기준으로 이루어집니다.
- 객체가 생성될 때 참조 카운트가 1로 시작됩니다.
- 객체를 참조(또는 소유)하는 다른 곳이 생기면 참조 카운트가 증가합니다.
- 참조가 끝나면 참조 카운트가 감소합니다.
- 참조 카운트가 0이 되면, ARC는 해당 객체가 더 이상 사용되지 않는다고 판단해 메모리에서 해제합니다.
Swift에서 ARC의 예시
class Person {
var name: String
init(name: String) {
self.name = name
print("\(name) called")
}
deinit {
print("\(name) deinitialized")
}
}
func createPerson() {
let jerry = Person(name: "Jerry")
print("Inside Function: \(jerry.name)")
}
createPerson()
코드 설명
- Person 클래스는 이름(name) 속성을 가지고 있으며, 생성될 때 init 초기화 메서드가 실행됩니다.
- deinit 메서드는 객체가 메모리에서 해제될 때 실행되는 함수로, 객체가 메모리에서 해제될 때를 알려주기 위해 추가했습니다.
- createPerson() 함수 내부에서 jerry라는 Person 객체를 생성합니다.
- createPerson() 함수가 끝나면 jerry을 참조하는 코드가 더 이상 없기 때문에 참조 카운트가 0이 되고, ARC에 의해 jerry 객체는 메모리에서 해제됩니다. 그러면 deinit이 실행되어 콘솔에 "Jerry deinitialized." 메시지가 출력됩니다.
순환 참조 문제
간혹 객체들이 서로를 참조하는 경우(순환 참조)에는 ARC가 제대로 동작하지 않을 수 있습니다. 이럴 때는 **약한 참조(weak reference)**나 **미소유 참조(unowned reference)**를 사용해 ARC가 순환 참조를 해결할 수 있도록 해줘야 합니다.
class Person {
var pet: Pet?
deinit {
print("Person has been deinitialized.")
}
}
class Pet {
weak var owner: Person? // 순환 참조 방지
deinit {
print("Pet has been deinitialized.")
}
}
func createRelationship() {
let person = Person()
let pet = Pet()
person.pet = pet
pet.owner = person // 순환 참조 발생
print("Relationship created")
}
createRelationship()
// 'person'과 'pet'은 더 이상 참조되지 않으므로 메모리에서 해제됩니다.
위의 예제에서 순환 참조 문제가 발생하는 이유는 두 객체가 서로를 강하게 참조하고 있기 때문입니다. Swift의 **Automatic Reference Counting (ARC)**는 객체를 참조하는 모든 강한 참조가 사라질 때 그 객체를 메모리에서 해제합니다. 하지만 순환 참조가 발생하면 참조 카운트가 0이 되지 않아 객체가 메모리에서 해제되지 않습니다.
순환 참조 문제 발생 원리
- Person 객체가 Pet 객체를 강하게 참조합니다:
- person.pet = pet 구문에서 Person 인스턴스(person)의 pet 속성이 Pet 인스턴스를 참조하게 됩니다. 이때 person은 pet을 강하게 참조합니다.
- Pet 객체도 Person 객체를 강하게 참조합니다:
- pet.owner = person 구문에서 Pet 인스턴스(pet)의 owner 속성이 Person 인스턴스를 참조하게 됩니다. 이 경우 pet도 person을 강하게 참조하게 됩니다.
이제 두 객체는 서로를 강하게 참조하고 있기 때문에, person과 pet이 모두 참조가 해제되어야 메모리에서 삭제될 수 있지만 각 객체가 서로를 참조하고 있기 때문에 참조 카운트가 0이 되지 않는 문제가 발생합니다. 즉, 둘 다 강하게 참조하고 있어서 어느 한쪽도 메모리에서 해제되지 않는 상태가 됩니다. 이 상태를 **순환 참조(Circular Reference)**라고 합니다.
해결 방법: 약한 참조(weak) 사용
순환 참조 문제를 해결하려면 둘 중 하나의 참조를 **약한 참조(weak reference)**로 만들어줘야 합니다. 약한 참조는 참조 카운트를 증가시키지 않기 때문에, 둘 중 하나가 메모리에서 해제될 때, 남은 약한 참조는 nil이 됩니다.
class Person {
var pet: Pet?
deinit {
print("Person has been deinitialized.")
}
}
class Pet {
weak var owner: Person? // 약한 참조로 순환 참조 방지
deinit {
print("Pet has been deinitialized.")
}
}
'정보 > 레벨 0' 카테고리의 다른 글
PNG와 JPG 차이점 (0) | 2024.10.31 |
---|---|
가상 메모리(Virtual Memory)의 개념과 동작 원리에 대해 설명해주세요. (2) | 2024.10.04 |
암호화와 보안의 기본 개념, iOS 앱 보안을 위한 방안에 대해 설명해주세요. (2) | 2024.10.04 |
동시성 프로그래밍의 개념과 iOS에서의 동시성 처리 방식에 대해 설명해주세요. (5) | 2024.10.02 |
자료구조의 종류와 iOS 개발에서 자주 사용되는 자료구조에 대해 설명해주세요. (5) | 2024.10.02 |