가비지 컬렉션(Garbage Collection, GC)이란?
가비지 컬렉션(Garbage Collection)은 컴퓨터 프로그래밍에서 사용되는 메모리 관리 기법 중 하나로, 프로그램이 동적으로 할당한 메모리 중에서 더 이상 사용되지 않는 메모리를 자동으로 탐지하고 회수하는 과정을 말합니다.
이를 통해 프로그래머는 명시적으로 메모리를 해제하는 작업에 신경쓰지 않아도 되므로 메모리 누수나 잘못된 메모리 참조와 같은 일부 버그를 방지할 수 있습니다.
가비지 컬렉션은 대부분의 고급 프로그래밍 언어에서 지원되며, 자바(Java), C#(C Sharp), 파이썬(Python), 자바스크립트(JavaScript) 등 많은 언어에서 기본적으로 가비지 컬렉션을 제공합니다.
힙 영역의 구성 요소 및 동작 방식
가비지 컬렉션은 Mark and Sweep 알고리즘을 사용하여 루트에서부터 시작하여 접근 가능한 객체를 식별하고 접근 불가능한 객체를 제거하는 과정으로, 힙 영역을 대상으로 수행되며 힙 영역은 Eden, Survivor, Old Generation 세 영역으로 구분되어 있습니다. 각 영역은 다른 방식과 빈도로 가비지 컬렉션이 수행됩니다.
Eden 영역은 객체가 처음 생성되는 공간으로, 가비지 컬렉션이 가장 자주 발생하는 영역입니다. Eden 영역이 가득 차면 Minor GC가 실행되어 살아남은 객체들을 Survivor 영역으로 이동시키고, 나이가 많은 객체들은 Old Generation 영역으로 이동됩니다.
Survivor 영역은 Minor GC에서 살아남은 객체들이 잠시 머무는 장소로, Survivor0와 Survivor1이라는 두 개의 영역으로 구성되어 있습니다. Minor GC가 발생할 때마다 살아남은 객체들은 비어있는 Survivor 영역으로 이동하고, 나이가 많은 객체들은 Old Generation 영역으로 이동됩니다.
Old Generation 영역은 오래된 객체들이 모여 있는 영역으로, 가비지 컬렉션이 가장 적게 일어나는 곳입니다. Old Generation 영역이 가득 차면 Major GC(또는 Full GC)가 발생하여 참조되지 않는 객체들을 한꺼번에 삭제합니다. Major GC는 시간이 오래 걸리고 모든 스레드가 일시적으로 멈추는 "Stop-the-World" 현상이 발생합니다.
가비지 컬렉션 진행 단계
1. 가비지 검색 (Marking)
가비지 컬렉션 시스템은 모든 객체를 순회하며 참조 가능한 객체를 마킹(Marking)합니다. 이 단계에서는 일반적으로 특정 객체를 가리키는 변수나 포인터 등을 추적하여 해당 객체를 마킹하며 마킹되지 않은 객체는 가비지로 간주됩니다.
2. 가비지 식별 (Sweeping)
마킹된 객체를 제외한 나머지 객체는 가비지로 간주됩니다. 가비지 식별 단계에서는 가비지로 표시된 객체의 메모리를 해제하여 다시 사용 가능한 상태로 만듭니다. 이 단계에서는 메모리 회수를 위해 사용되지 않는 객체를 식별하고, 해당 객체의 메모리를 해제합니다.
3. 메모리 재할당 (Compaction, 선택적)
일부 가비지 컬렉션 시스템은 객체들을 메모리의 연속적인 공간에 배치하는 작업을 수행하여 메모리 단편화를 방지하고 성능을 향상시킬 수 있습니다. 이 단계는 선택적으로 적용되며, 컬렉션 시스템에 따라 다를 수 있는데, 메모리 재할당을 통해 객체들이 연속된 메모리 영역에 위치하면 메모리 접근 시간이 감소하고, 메모리 사용 효율성이 향상될 수 있습니다.
가비지 컬렉션의 종류와 동작 방식
가비지 컬렉션은 메모리 관리를 자동화하기 위해 사용되는 여러 종류의 알고리즘이 있습니다. 대표적으로 Tracing과 Reference counting이라는 두 가지 방식이 있습니다.
1. Tracing
Tracing은 루트 객체로부터 접근 가능한 객체를 추적하고, 접근 불가능한 객체를 식별하여 제거하는 방식입니다. 이 방식에는 mark-and-sweep과 tri-color marking이라는 두 가지 알고리즘이 사용됩니다.
mark-and-sweep 알고리즘은 가장 간단하고 전통적인 방식으로, 가비지 컬렉션의 기본 개념입니다. 이 알고리즘은 루트 객체 집합(root set)에서부터 시작하여 접근 가능한 객체를 표시(mark)하고, 표시되지 않은 객체는 가비지로 간주하여 삭제(sweep)합니다. mark-and-sweep 알고리즘은 단순하고 효과적이지만, 가비지 컬렉션을 수행하는 동안 전체 시스템을 일시적으로 멈추어야 한다는 단점이 있습니다.
tri-color marking은 mark-and-sweep 알고리즘의 성능과 멈춤 시간 단점을 개선한 방식입니다. 이 알고리즘은 객체를 흰색, 회색, 검은색으로 분류하며, 회색으로 표시된 객체들을 중심으로 참조하는 객체들을 회색으로 표시합니다. 회색 객체가 없을 때까지 이 과정을 반복하고, 남은 흰색 객체는 접근 불가능한 객체로 간주하여 삭제합니다. tri-color marking은 mark-and-sweep보다 성능이 좋으며, 가비지 컬렉션을 즉시 수행할 수 있어 더 나은 응답성을 제공합니다.
2. Reference counting
Reference counting은 객체가 참조된 횟수를 카운팅하여 해당 객체의 참조 횟수가 0이 되면 가비지로 간주하여 제거하는 방식입니다. 각 객체는 참조 카운터(reference count)를 유지하며, 참조가 추가될 때마다 카운터를 증가시키고, 참조가 삭제될 때마다 카운터를 감소시킵니다. 카운터가 0이 되면 해당 객체는 더 이상 사용되지 않는 것으로 판단하여 메모리에서 해제됩니다.
Reference counting은 간단하고 즉각적으로 메모리를 해제할 수 있지만, 객체의 참조 횟수를 관리하는 비용이 발생하며, 순환 참조(circular reference)와 같은 상황에서는 메모리 누수의 문제가 발생할 수 있습니다.
가비지 컬렉션을 최적화하는 방법
Collection의 크기를 예측하여 설정하기: Collection 객체를 생성할 때 초기 용량을 예측하여 설정하는 것이 좋습니다. 초기 용량을 충분히 설정하면 Collection 내부에서 배열을 반복적으로 생성하고 복사하는 작업을 줄일 수 있어 가비지 생성과 성능 저하를 방지할 수 있습니다.
Stream을 사용하기: Stream API를 사용하면 컬렉션을 처리하는 과정에서 중간 결과를 저장하기 위한 임시 컬렉션을 생성하지 않아도 됩니다. 이를 통해 가비지 생성을 줄이고 성능을 향상시킬 수 있습니다. 또한 Stream API는 병렬 처리를 지원하기 때문에 멀티코어 환경에서 성능을 최적화할 수 있습니다.
String의 사용 최적화하기: String 객체는 불변성을 가지기 때문에 문자열 연산이 발생할 때마다 새로운 객체를 생성합니다. 문자열 연결이나 수정이 자주 발생하는 경우에는 StringBuilder나 StringBuffer와 같은 가변 클래스를 사용하여 성능을 개선할 수 있습니다.
불변성(Immutability) 활용하기: 불변 객체는 한 번 생성되면 내부 상태가 변하지 않기 때문에 가비지 컬렉션의 대상이 되지 않습니다. 불변 객체는 스레드 안전하고 동기화가 필요 없으므로 병렬 처리에 유리합니다. 객체의 불변성을 유지하고 변경이 필요한 경우에는 새로운 객체를 생성하는 방식을 고려해야 합니다.
불필요한 Collection의 생성 피하기: Collection 객체를 생성할 때는 필요한 경우에만 생성하고, 가능하면 재사용하거나 null로 초기화해야 합니다. 또한 Collection을 반환하는 메서드에서는 null 대신 빈 Collection 객체를 반환하는 것이 좋습니다. 이를 통해 불필요한 객체 생성과 메모리 사용을 줄일 수 있습니다.
이러한 최적화 방법들은 가비지 컬렉션의 효율성을 향상시키고 성능을 개선하는 데 도움을 줍니다. 개발자는 자신의 애플리케이션에 적합한 최적화 방법을 선택하여 메모리 사용과 가비지 컬렉션의 영향을 최소화할 수 있습니다.
'용어 사전' 카테고리의 다른 글
스파이럴(Spiral)이란? (0) | 2023.06.30 |
---|---|
스크럼(Scrum)이란? (0) | 2023.06.29 |
워터폴(폭포수, Waterfall)이란? (0) | 2023.06.28 |
애자일(Agile)이란? (0) | 2023.06.27 |
리팩터링(Refactoring)이란? (0) | 2023.06.25 |
씩 프로비저닝(Thick provisioning)이란? (0) | 2023.06.24 |
씬 프로비저닝(Thin provisioning)이란? (0) | 2023.06.23 |
하이퍼바이저(Hypervisor)란? (0) | 2023.06.22 |