[C++] 가비지 콜렉션 vs 참조 카운팅
카테고리: Cpp
이 글은 가비지 콜렉션과 참조 카운팅을 공부하고 정리한 글입니다.
가비지 컬렉션(Garbage Collection, GC)
- Java와 C#에서 지원
- 보통 트레이싱 가비지 컬렌션(Tracing Garbage Collection)을 의미
- 메모리 누수를 막으려는 시도
- 주기적으로 컬렉션 실행
- 충분한 여유 메모리가 없을 때 컬렉션이 실행됨
- 스케쥴에 따라 또는 수동으로도 실행가능
- 매 주기마다, GC는 루트를 확인함
- 전역 변수
- 스택
- 레지스터
- 힙에 있는 개체에 루트를 통해 접근할 수 있는지 판단
- 접근할 수 없다면, 가비지로 간주해서 해제
- 되게 비용이 많이 드는 작업이지만 C#에서 최적화를 했음
가비지 콜렉션의 문제점
- 사용되지 않는 메모리를 즉시 정리하지 않음
- GC가 메모리를 해제해야 하는지 판단하는 동안 애플리케이션이 멈추거나 버벅일 수 있음
참조 카운팅(Reference Counting, RefCounting)
- 가비지 컬렉션처럼, 개체에 대한 참조가 없을 때 개체가 해제됨
- 언제든 참조 횟수를 활용해서 특정 개체가 몇 번이나 참조되고 있는지 판단 가능
- 어떤 개체 A를 다른 개체 B가 참조할 때 횟수가 늘어남
- B가 참조를 그만둘 때 횟수 줄어듦
- B가 범위를 벗어나는 경우
강한(Strong) 참조
- 강한 참조란 개체 A가 개체 B를 참조할 때, 절대 소멸되지 않음을 의미
- 강한 참조의 수를 저장하기 위해 강한 참조 카운트를 사용
- 일반적으로 새 인스턴스, 즉 개체에 대한 참조를 만들 때 강한 참조 횟수가 늘어남
- 강한 참조 횟수가 0이 될 때 해당 개체는 소멸됨
약한(Weak) 참조
- 약한 참조는 원시 포인터 해제에 영향을 끼치지 않음
- 약한 참조 카운트는 약한 참조의 수를 저장하는 데 사용됨
- 약한 참조로 참조되는 개체는 강한 참조 카운터가 0이 될 때 소멸됨
- 순환 참조 문제의 해결책
참조 카운팅의 문제점
- 참조 횟수는 너무 자주 바뀜
- 멀티 쓰레드 환경에서 안전하려면, lock이나 원자적(atomic) 연산이 필요
- 순환(circular) 참조
- 개체 A가 개체 B를 참조
- 개체 B가 개체 A를 참조
- 절대 해제되지 않음
GC나 RefCount를 쓰면 메모리 누수가 없다?
- 전통적인 메모리 누수는 없음
- 하지만 여전히 메모리 누수가 발생할 수 있음
- 예) 순환 참조
가비지 컬렉션 vs 참조 카운팅
- 가비지 컬렉션
- 사용하기 확실히 더 쉬움
- 실시간 또는 고성능 프로그램에 적합하지 않음
- 참조 카운팅
- 여전히 사용하기 쉬움
- 실시간 또는 고성능 프로그램에 적합
- 멀티스레드 환경에서는 순수한 포인터보다 훨씬 느림
참조
💻 열심히 공부해서 작성 중이니 오류나 틀린 부분이 있을 경우
언제든지 댓글 혹은 메일로 알려주시면 감사하겠습니다! 😸
댓글 남기기