가비지 컬렉션(GC, Garbage Collection) 알고리즘

 

이번에는 Garbage Collection 알고리즘에 대해 알아보도록 하자.

GC를 수행하기 위해 Stop-The-World가 발생되고 이 때문에 애플리케이션의 지연 현상이 두드러지게 되었고, 이를 막기 위해 다양한 가비지 컬렉션 알고리즘이 나왔다.

 

Serial GC

싱글 스레드로 동작하며 Serial GC의 Young 영역은 이전 게시글에서 보았던 알고리즘(Mark-and-Sweep)대로 수행된다. 

Old 영역에서는 Mark-Sweep-Compaction 알고리즘이 사용되는데, 기존의 Mark-And-Sweep에 Compact라는 작업이 추가되었다. Compact는 heap 영역을 정리하기 위한 단계로 Sweep 후에 분산된 객체들을 Heap의 시작 주소로 모아 메모리가 할당된 부분과 그렇지 않은 부분으로 나눈다. 메모리 단편화를 막아주는 작업이다. 

더보기
https://mirinae312.github.io/develop/2018/06/04/jvm_gc.html

Mark-Sweep-Compaction

Mark : Root Space로부터 그래프 순회를 통해 연결된 객체들을 찾아내어 각각 어떤 객체를 참조하고 있는지 찾아서 마킹한다.
Sweep : 
Unreachable한 객체들을 heap에서 제거하는 과정

Compact : Sweep 후에 분산된 객체들을 Heap의 시작 주소로 모아 메모리가 할당된 부분과 그렇지 않은 부분으로 압축한다.

 

GC가 수행되는 동안 다른 스레드들은 작업을 모두 멈추는 Stop-The-World가 발생한다.

가장 오래된 GC이며 싱글 스레드가 GC를 수행하고 있으므로 다른 GC 알고리즘에 비해 시간이 많이 소요된다. 거의 사용되지 않는 GC 알고리즘이다. 

 

Parallel GC

기본적인 처리 과정은 Serial GC와 동일하지만, Young 영역의 Minor GC를 멀티 스레드로 수행함으로써 Serial GC에 비해 Stop-The-World 시간을 상당히 줄여준다. 멀티 프로세서 또는 멀티 스레드 머신에서 중간 규모부터 대규모의 데이터를 처리하는 애플리케이션을 위해 고안되었으며, 옵션을 통해 애플리케이션의 최대 지연 시간 또는 GC를 수행할 스레드의 개수 등을 설정해 줄 수 있다. 처리시간보다는 처리량에 초점을 맞춘 GC이기 때문에 Throughput GC라고도 부른다. Java 8까지 기본 가비지 컬렉터로 사용되었다. 

 

Parallel Old GC

Parallel Old GC는 Young 영역뿐만 아니라 Old 영역까지도 멀티 스레드 방식을 사용한다. Parallel GC와 비슷하나 Mark-Sweep-Compaction 알고리즘 대신 Mark-Summary-Compaction 알고리즘을 사용한다. 

  • Mark : Old 영역을 region 이라는 논리적인 단위로 균일하게 나누고, 각 스레드들은 region 별로 사용되는 객체를 표시
  • Summary : Sweep 작업 중에 사용되는 객체를 식별하는 작업이 추가됨. region 단위로 작업을 수행하며 각 region 마다 사용되는 객체의 밀도(Density)를 평가 후 Dense prefix를 설정. 이후 Compaction 대상이 되는 region의 첫 번째로 사용되는 객체 주소를 찾아 저장하여 GC 수행 범위를 정한다. 
  • Compaction : 모든 스레드가 각 region을 할당받아 compaction을 수행.

 

CMS(Concurrent Mark Sweep) GC

CMS GC는 Parallel GC와 마찬가지로 멀티 스레드를 이용한다. 하지만 기존의 Serial GC나 Parallel GC와는 다르게 Mark Sweep 알고리즘을 Concurrent하게 수행하게 된다. 

이러한 CMS GC는 애플리케이션의 지연 시간을 최소화하기 위해 고안되었으며, 애플리케이션이 구동 중일 때 프로세서의 자원을 공유하여 이용 가능해야 한다. CMS GC가 수행될 때에는 자원이 GC를 위해서도 사용되므로 응답이 느려질 수는 있지만 응답이 멈추지는 않게 된다. 하지만 이러한 점 때문에 다른 GC 방식보다 메모리와 CPU를 더 많이 필요로 하며, Compaction 단계를 수행하지 않는다는 단점이 있다. Java 9버전부터 deprecated 되었고 Java 14에서는 사용이 중지되었다.

 

 

G1(Garbage First) GC 

CMS GC를 대체하기 위해 Java 7 버전에서 최초로 도된 GC로 Java 9+ 버전의 디폴트 GC이다. 

G1은 Garbage First의 약어로 Garbage만 있는 Region을 먼저 회수한다고 해서 붙여진 이름이다. 빈 공간 확보를 더 빨리 한다는 것은 조기 승격이나 급격히 할당률이 늘어나는 것을 방지하여 Old 영역을 비교적 한가하게 만들 수 있다. 

기존의 GC 알고리즘에서는 heap 영역을 물리적으로 Young 영역(Eden 영역과 2개의 Survivor 영역)과 Old 영역으로 나누어 사용하였다. G1 GC는 Eden 영역에 할당하고, Survivor로 copy하는 등의 과정을 사용하지만 물리적으로 메모리 공간을 나누지는 않는다. 대신 Region이라는 개념을 새로 도입하여 heap을 균등하게 여러 개의 지역으로 나누고, 각 지역을 역할과 함께 논리적으로 구분하여(Eden 지역인지, Survivor 지역인지, Old 지역인) 객체를 할당한다. 

G1 GC에서는 Eden, Survivor, Old 역할에 더해 Humongous와 Available/Unused라는 2가지 역할을 추가하였다. 

Humongous는 Region 크기의 50%를 초과하는 큰 객체를 저장하기 위한 공간을 의미하며, Available/Unused은 아직 사용되지 않은 Region을 의미한다.

 

 

 


 

 

 

[Reference]

더보기

'Development > Java' 카테고리의 다른 글

자바 가상 머신 JVM(Java Virtual Machine)  (0) 2024.12.23
가비지 컬렉션 (GC, Garbage Collection)  (0) 2024.12.17
불변 객체(Immutable Object)  (0) 2024.11.21