GC(Garbage Collectors)

나르·2023년 2월 21일
0

JAVA

목록 보기
14/18
post-thumbnail
post-custom-banner

GC 란?


GC는 Java 프로세스가 한정된 메모리를 효율적으로 사용할 수 있게 하는 JVM 의 메모리 관리 작업입니다.
JVM은 자동으로 힙 메모리에서 사용하지 않는 객체를 식별, 수집, 해제하여, 프로그래머가 직접 메모리를 관리하는 부담을 줄여줍니다.

Java Heap

위 그림은 Jdk 7 이전의 Heap 메모리 구조입니다.

  • Eden: 새로 생성한 대부분의 객체가 위치하는 곳
  • S0, S1: Eden 영역에서 GC가 한번 발생한 후 살아남은 객체들이 존재하는 곳
  • Old: Young Generation에 대한 GC가 반복되는 과정속에 Tenuring Threshold 만큼 살아남은 객체가 존재하는 곳
  • Perm: Class/Method 의 Meta 정보, static 변수/상수, JVM/JIT 관련 데이터 등들이 저장되는 곳

Java 8 이후로 permanent가 Native 영역인 Metaspace 로 변경되었고, 해당 영역에 있던 정보 중 static 변수/상수는 heap 영역으로 옮겨지면서 GC 대상에 포함되게 되었습니다.

Minor GC, Full GC

GC가 실행될 때, JVM은 프로세스의 모든 스레드를 일시 중지(stop the world) 하고 사용하지 않는 객체를 식별하고 수집합니다.
Full GC의 실행 시간은 상대적으로 Minor GC에 비하여 길기 때문에, GC 실행에 STW 가 1초 이상이 소요되게 되면 연계된 여러 부분에서 타임아웃이 발생할 수 있습니다.

때문에 JVM은 STW 시간을 최소화하고 성능을 향상시키기 위해 다양한 GC 알고리즘을 제공하고 있고, 적절한 GC 알고리즘을 선택하고 힙 크기를 조정하여 애플리케이션의 성능을 최적화할 수 있습니다.

(허나 대부분의 상황에서 GC 튜닝까지는 필요하지 않다는 것을 유의해야 합니다.)

GC 알고리즘


Serial GC (-XX:+UseSerialGC)

Java 5,6의 default GC 로 싱글 스레드로 동작하기 때문에 STW가 다른 GC에 비해 오래걸립니다. Serial GC는 적은 메모리와 CPU 코어 개수가 적을 때 적합한 방식이며, mark & sweep & compact 알고리즘을 사용합니다.

  • Mark는 Old 영역에 살아있는 객체, 즉 gc 대상이 아닌 객체에 대해 식별하는 역할을 합니다.
  • Sweep은 Heap의 앞 부분부터 mark 된 Object를 제외하고 제거합니다.
  • Compact는 Sweep 이후 비어있는 Heap 공간들을 연속되게 쌓이도록 힙의 앞 부분부터 채우는 과정입니다.

Parallel GC (-XX:+UseParallelGC)

Java 8의 default GC로, Serial GC와 기본적인 알고리즘은 같지만 Serial GC 는 단일 스레드인데에 비해 Parallel GC의 Minor GC는 멀티 스레드로 동작합니다.(Full GC는 동일)
Parallel GC는 메모리가 충분하고 코어의 개수가 많을 때 유리하며, Throughput GC라고도 부릅니다.

Parallel Old GC (-XX:+UseParallelOldGC)

Parallele GC를 업그레이드한 버전으로, Full GC 또한 병렬적으로 처리하며 mark & summary & compact 알고리즘을 사용합니다.
Summary 단계는 앞서 GC를 수행한 영역에 대해서 별도로 살아 있는 객체를 식별한다는 점에서 차이가 있습니다.

CMS GC (-XX:+UseConcMarkSweepGC)

CMS GC는 Full GC의 수행시간을 최소한으로 하는데 초점을 둔 GC 방식으로, STW 의 시간을 최소화 합니다.

  • Initial Mark : STW 현재 살아남은 객체를 탐색하는데, 클래스 로더에서 가장 가까운 객체(GC ROOT에서 참조하는 객체)들만 우선적으로 탐색하기 때문에 STW발생 시간이 매우 짧습니다.
  • Concurrent Mark : Initial Mark에서 탐색한 객체들이 참조하고 있는 객체를 찾아가며, GC의 대상인지 판별합니다.
  • ReMark : STW Concurrent Mark 과정 중 새로 생성된 객체나, 참조자 끊기는 등 변경된 객체가 있는지 다시한번 검사합니다. (멀티스레드로 동작하기 때문에 STW 시간이 짧음)
  • Concurrent Sweep : STW 없이 Remark 단계까지 검증이 완료된 GC대상 객체들을 삭제합니다.

하지만 CMS GC는 다른 GC 방식보다 메모리와 CPU를 더 많이 사용하고, Compaction 작업을 기본적으로 진행하지 않기 때문에 메모리 단편화에 대한 문제를 신경써야 합니다.

만약 연속적인 메모리 할당이 불가능할 정도로 메모리 단편화가 진행되었다면 Compaction 작업을 수행해야 하는데, 해당 작업은 다른 GC에서의 Compaction작업에 비해 STW 시간이 길어집니다.
따라서 CMS GC를 사용할때는 Compaction 작업이 얼마나 자주, 오래 실행되는지를 검토 후에 사용해야합니다.

Java 9 부터 deprecated 되었고 Java 14 에서는 중지되었습니다.

G1(Garbage First) GC

Java 9 의 default GC로, G1 GC는 장기적으로 문제가 야기될 가능성이 있는 CMS GC의 대체 방안으로 고안되었으며, 성능상 뛰어나다는 장점이 있습니다.

G1 GC는 메모리를 바둑판처럼 각각의 영역으로 구분하고 각 영역에 객체를 할당하여 GC를 실행합니다.
그러다가, 해당 영역이 꽉 차면 다른 영역에서 객체를 할당하고 GC를 실행합니다.
즉 기존의 Young, Old 영역 대신 힙 메모리 영역 자체를 Region 이라는 논리적인 단위로 나눠서 관리하며, 이렇게 나뉜 Region에 특정 역할(Eden,Survivor,Old 등)을 동적으로 부여하는 방식입니다.

ZGC (-XX:+UseZGC)

ZGC 는 JDK 15에서 기준 Production Ready 상태로, 조금 더 큰 메모리(8MB ~ 16TB) 에서 효율적으로 Garbage Collect 하기 위한 알고리즘입니다.

ZGC : a good fit for server applications, where large heaps are common, and fast application response times are a requirement.

ZGC는 STW 시간을 최대한 적게(10ms 이하로) 가져가기 위해, Mark 의 시작과 끝, 재배치에만 STW가 발생합니다.

  • Mark Start : STW ZGC의 Root에서 가리키는 객체 Mark 표시
  • Concurrent Mark/Remap : 객체의 참조를 탐색하면서 모든 객체에 Mark 표시
  • Mark End : STW 새롭게 들어온 객체들에 대해 Mark 표시
  • Concurrent Pereare for Relocate : 재배치하려는 영역을 찾아 Relocation Set에 배치
  • Relocate Start : STW 모든 Root 참조의 재배치를 진행하고 업데이트
  • Concurrent Relocate : 이후 Load Barriers 를 사용하여 모든 객체를 재배치 및 참조 수정

ZGC doesn't get rid of stop-the-world pauses completely.
The collector needs pauses when starting marking, ending marking and starting relocation.
But this pauses are usually quite short - only a few milliseconds.

G1 GC 와 비슷하게 ZGC 또한 힙 영역을 리전으로 분류합니다. 각 리전 타입에 따라 저장될 수 있는 객체의 크기는 아래와 같습니다.
만약 6M 짜리 객체가 들어온다면, 4M 이상이므로 Large Page에 할당되게 됩니다.

ZGC는 GC 메타데이터를 객체의 메모리 주소에 표시합니다(Colored Pointers).
ZGC는 64비트만 지원하는데, 메모리의 주소 파트로 42비트(4TB)를 사용하고 다른 4비트를 하기 GC metadata 를 저장하는 용도로 사용합니다.

  • Finalizable: finalizer를 통해서만 참조되는 Objectd의 Garbage
  • Remapped: 재배치 여부를 판단하는 마크
  • Marked 1(or 0): Live Object

ZGC 관련 내용은 아래 아티클에 잘 나와있습니다.
ZGC에 대해서
Getting started with Z Garbage Collector (ZGC) in Java 11 [Tutorial]
ZGC Notes: Colored Pointers


Ref.

JVM Garbage Collectors
JDK 18 G1/Parallel/Serial GC changes
Garbage Collection

profile
💻 + ☕ = </>
post-custom-banner

0개의 댓글