학습
Dart 가비지 컬렉션 이해
Dart 가비지 컬렉션 이해 — 고급
가비지 컬렉션 이해
1. 도입 (왜 배워야 하는가)
가비지 컬렉션(Garbage Collection, GC)은 프로그램에서 더 이상 사용되지 않는 메모리를 자동으로 회수하는 프로세스입니다. Dart와 같은 현대적인 언어에서는 메모리 관리가 자동으로 이루어지기 때문에 개발자는 메모리 할당과 해제에 대해 덜 걱정할 수 있습니다. 그러나 가비지 컬렉션이 어떻게 작동하는지 이해하지 못하면 다음과 같은 문제가 발생할 수 있습니다.
- 메모리 누수: 개발자가 객체를 의도적으로 해제하지 않으면 메모리 사용량이 지속적으로 증가하여 애플리케이션이 느려지거나 중단될 수 있습니다.
- 성능 저하: 가비지 컬렉션이 너무 자주 발생하면 애플리케이션의 성능에 부정적인 영향을 미칠 수 있습니다. 이를 이해하고 조절하지 않으면 사용자의 경험이 나빠질 수 있습니다.
이해를 바탕으로 가비지 컬렉션을 잘 활용하면 안정적이고 효율적인 애플리케이션을 개발할 수 있습니다.
2. 핵심 개념 설명
가비지 컬렉션의 주요 개념은 다음과 같습니다.
| 용어 | 정의 |
|---|---|
| 가비지 | 더 이상 참조되지 않는 객체로, 메모리에서 해제될 수 있는 상태입니다. |
| 참조 | 객체가 메모리에 할당되어 있는 경우, 이를 참조하는 변수나 다른 객체를 의미합니다. |
| 힙(Heap) | 동적으로 할당된 객체들이 저장되는 메모리 영역입니다. |
| 스택(Stack) | 지역 변수와 함수 호출 정보를 저장하는 메모리 영역입니다. |
비유
가비지 컬렉션은 마치 청소부가 사무실에서 필요 없는 물건들을 정리하는 것과 같습니다. 사무실 내에서 더 이상 사용되지 않는 물건(가비지)을 정리하여 공간을 확보하는 것처럼, 프로그램에서 더 이상 사용되지 않는 메모리도 정리하여 새로운 객체를 위한 공간을 만듭니다.
3. 기본 코드 예제
가비지 컬렉션을 이해하기 위한 기본 코드 예제를 살펴보겠습니다.
class Person {
String name;
Person(this.name);
}
void main() {
Person john = Person('John');
// john 객체는 이제 더 이상 사용되지 않음
john = null; // 이 시점에서 'john' 객체는 가비지로 간주됨
// 가비지 컬렉션이 호출될 수 있음
print('가비지 컬렉션이 호출될 수 있습니다.');
}
실행 결과:
가비지 컬렉션이 호출될 수 있습니다.
코드 동작 설명
Person클래스를 정의하고,name속성을 초기화하는 생성자를 만듭니다.main함수에서john이라는Person객체를 생성합니다.john객체를 더 이상 사용하지 않기 위해null로 설정합니다. 이 시점에서john객체는 더 이상 참조되지 않으므로 가비지로 간주됩니다.- 마지막 줄에서 가비지 컬렉션이 호출될 수 있음을 알리는 메시지를 출력합니다.
- 가비지 컬렉션은 메모리를 자동으로 관리하여 개발자의 부담을 줄여줍니다.
- 객체가 더 이상 참조되지 않을 때 가비지로 간주되어 메모리에서 해제됩니다.
- 메모리 누수를 방지할 수 있도록 객체를 명확히 해제하는 것이 중요합니다.
- 다음에 학습하면 좋은 주제는 메모리 최적화 기법과 Dart의 비동기 프로그래밍입니다.
4. 실전 활용 예제
예제 1: 쇼핑몰에서 장바구니를 구현할 때
장바구니에 상품을 추가하고, 사용자가 장바구니를 비우는 경우 해당 상품 객체는 더 이상 필요 없으므로 가비지로 처리될 수 있습니다.
class Product {
String name;
Product(this.name);
}
class Cart {
List<Product> items = [];
void addItem(Product product) {
items.add(product);
}
void clearCart() {
items.clear(); // 장바구니를 비우면 Product 객체들은 가비지로 처리될 수 있음
}
}
void main() {
Cart cart = Cart();
cart.addItem(Product('Apple'));
cart.addItem(Product('Banana'));
cart.clearCart(); // 장바구니를 비움
}
예제 2: 사용자가 로그아웃할 때
사용자가 로그아웃하면 관련된 사용자 정보를 담고 있던 객체를 해제하여 메모리를 확보합니다.
class User {
String username;
User(this.username);
}
void main() {
User user = User('Alice');
// 로그인 상태에서 사용자 정보를 사용
print('Logged in as: ${user.username}');
// 로그아웃 시
user = null; // 더 이상 필요 없으므로 가비지로 처리됨
}
5. 흔한 실수와 주의사항
실수 1: 객체를 해제하지 않고 계속 참조
class User {
String username;
User(this.username);
}
void main() {
User user = User('Alice');
// 사용자 객체를 해제하지 않음
// 메모리 누수 발생 가능
}
올바른 코드:
user = null; // 더 이상 필요 없을 때 객체를 해제해야 함
실수 2: 너무 자주 GC를 호출하기
void main() {
for (int i = 0; i < 100000; i++) {
var temp = Person('Temporary $i');
// GC를 명시적으로 호출할 수 없지만
// 너무 많은 객체를 생성하면 성능 저하가 발생할 수 있음
}
}