안녕하세요.

오늘은 Garbage Collection(Collector)에 대해서 포스팅해보려고 합니다.

 

 


 

JVM의 Heap Area에 남은 더 이상 사용하지 않는 인스턴스를 Garbage라고 하며,

이 Garbage를 효과적으로 처리하는 작업을 Garbage Collection. 이를 수행하는 프로그램을 Garbage Collector 라고 합니다.

 

예를 들면 아래와 같은 코드가 있을 때.. 

// 지역 변수일 때
String text1 = "hello";

text1 = "Java";

이전 포스팅에서 알아본 바에 따르면, 위 코드는

 

 

text1은 Stack 영역에 저장이 되고 "hello" 문자열은 Heap 영역에 저장이 됩니다.

text1은 Heap영역의 주소 값을 가지고 있으며 그 주소 값은 hello를 가르키게 됩니다.

이후에 text1이 가르키는 주소 값을 "Java"로 변경했습니다. 

 

그러면 Heap 영역에 저장된 "hello" 값은 어떻게 될까요??

이게 바로 Garbage가 됩니다.

지금은 하나지만, 프로젝트가 규모가 커질수록 쌓이는 Garbage들이 많아질텐데, 이를 관리 안해주면 메모리를 많이 차지하고 있겠죠?

이를 자동으로 관리해주는 프로그램을 Garbage Collector라고 합니다.

 

Garbage Collector는 두 가지의 가설을 전제로 만들어졌습니다.

1. 대부분의 객체는 금방 unreachable 상태가 된다. < 금방 garbage 상태가 된다. >

2. Old 객체가 Young 객체를 참조하는 일은 아주 적게 일어난다. 

 

쉽게 설명하자면 "대부분의 객체가 금방 아무도 참조하지 않는 상태가 되며", "생성된 지 오래된 객체가 최근에 생성된 객체를 참조하는 일은 아주 적게 일어납니다."

라는 것을 전제로 설계되어 만들어 졌다는 뜻입니다.

 

Garbage Collection의 동작 방식을 알아보기 전에 Mark and Sweep, Stop the World 작업에 대해서 알아보겠습니다.

 

- Mark: 사용되는 메모리와 사용되지 않는 메모리를 식별하는 작업. ( Reachable 상태와 Unreachable 상태 식별 )

- Sweep: Mark 단계에서 식별된 사용되지 않는 메모리를 제거하는 작업.

- Stop the World: GC 실행을 위해 GC 쓰레드를 제외한 모든 쓰레드의 작업을 멈추는 것을 말합니다. Application이 잠깐 중지되며, GC 알고리즘의 종류에 따라 STW 시간이 다릅니다.

- Compact: GC 알고리즘의 종류에 따라서 존재하는 작업으로, Sweep 후 분산되어 있는 객체들을 Heap의 한 곳(시작 주소)로 모아 메모리의 분산화를 막아줍니다.

 

 

Java 8 버전을 기준으로, Heap영역은 Young Generation과 Old Generation. 이 두 영역으로 나누어집니다.

 

- Young Generation: 새롭게 생성된 객체가 할당되는 영역으로, 이 영역에 대한 GC를 Minor GC라고 합니다.

- Old Generation: Young 영역에서 Reachable 상태를 유지해 살아남은 객체가 복사되는 영역으로, 이 영역에 대한 GC를 Major GC라고 합니다. 

 

# Garbage Collector 동작 과정

1. 새로운 객체는 Eden 영역에 할당됩니다.

 

2. Eden 영역이 꽉차면 Minor GC가 발생하여 Mark and Sweep 과정이 일어납니다.

 

3. Unreachable로 식별된 객체들은 삭제되며 Reachable 상태로 식별된(마킹된) 객체들은 survivor 영역으로 이동하며  Age값이 증가합니다.

< 규칙 :: survivor0 영역에 객체가 있으면, survivor1 영역은 무조건 비워져있어야 합니다. 반대도 마찬가지. >

- 다음 Minor GC가 발생하면 반대편 survivor 영역으로 이동합니다.

 

4. 2~3의 과정이 반복되어, 객체의 AGE값이 특정 값. 임계치에 도달하게 되면 Old Generation으로 이동하게 됩니다. 이를 Promotion이라고 합니다.

 

5. Old Generation이 꽉 차면 Major GC가 발생합니다.

 

 

GC의 종류(알고리즘의 종류)는 다음과 같습니다.

 

1. Serial GC

- GC를 처리하는 쓰레드가 1개라서 다른 GC에 비해 STW 시간이 깁니다.

- Mark and Sweep 후 Compact 과정이 포함됩니다. 

 

2. Parallel GC

- Java 8의 Default GC로, Young 영역의 GC를 멀티 쓰레드로 수행합니다.

- Serial GC에 비해 STW 시간이 짧습니다.

 

3. Parallel Old GC

Parallel GC를 개선한 것으로, Old 영역에서도 멀티 쓰레드로 GC를 수행합니다.

- Mark-Summary-Compact 알고리즘을 수행합니다.

< Sweep: 단일 쓰레드, Summary: 멀티 쓰레드 >

 

4. Concurrent Mark Sweep GC

- STW 시간을 줄이기 위해 고안된 방법으로, 다음 4단계를 거칩니다.

1) Initial Mark: GC Root에서 참조하는 객체들만 식별합니다.

2) Conccurent Mark: 이전 단계에서 식별된 객체들이 참조하는 모든 객체를 추적합니다.

3) Remark: 이전 단계에서 식별한 객체들을 다시 추적하여, 추가되거나 끊긴 객체를 확정합니다.

4) Concurrent Sweep: 최종적으로 Unreachable 객체를 삭제합니다.

- 과정이 많기 때문에 CPU의 부하가 커진다는 단점이 있습니다.

 

5. G1 GC (Garbage First)

- Concurrent를 개선한 것으로, 이전 GC들은 큰 용량의 메모리 적합하지 않습니다. ( Root Set 부터 탐색하기때문에 용량이 크면 탐색 시간이 길어짐 )

- 큰 Heap 메모리에서 짧은 GC 시간을 보장하는 데에 목적이 있습니다.

- Heap 메모리를 물리적인 영역(Young-Old Generation)으로 나눈게 아니라, Region이라는 일정한 크기의 영역으로 나눕니다.

- Region은 최대 2048개로 나뉠 수 있으며, 각각 1~32MB의 크기를 가집니다.

- 핵심은 Heap을 동일한 크기의 Region으로 나누고, Garbage가 많은 Region에 대해 우선적으로 GC를 수행하는 것 입니다.

 

 


 

Garbage Collector가 무엇인지, 어떻게 동작하는지, 종류로는 어떤 것이 있는 지에 대해 알아봤습니다.

 

 

참고 사이트

https://mangkyu.tistory.com/119

https://www.youtube.com/watch?v=Fe3TVCEJhzo

+ Recent posts