본문 바로가기
개발공부/Java

[JVM GC] GC 종류와 동작 방식과 G1GC 튜닝 포인트

by sangyeon 2022. 1. 5.
728x90

1. JVM GC 동작 순서

GC를 수행할 때에는 아래와 같이 Three-Step으로 이루어진다.

 

(1) Heap 영역에 존재하는 객체들에 대하여 접근 가능 여부를 확인한다.

(2) GC Root에서 시작하여 참조값을 따라가며 접근 가능한 객체들에 Mark 하는 과정을 진행한다.

(3) Mark되지 않은 객체들은 제거(Sweep) 대상이 되고 해당 객체들을 제거한다.

 

* 아래는 GC Root에서 접근 가능한 객체를 판단하는 과정에 대한 설명 

이미지 출처 - https://velog.io/@zaccoding/JVM-Garbage-CollectionGC

  • GC Root에서 참조하고 있는 객체를 찾고 또 그 객체가 참조하는 객체를 찾아가며 Mark 한다.
  • Mark되지 않은 객체는 접근 불가능한 객체(Unreachable Object)로 판단하고 제거(Sweep) 된다.
  • Sweep 과정에 의해 삭제되면 메모리 단편화가 발생하는데 이는 Compact를 통해 빈자리를 채워준다.

이미지 출처 - https://medium.com/@joongwon/jvm-garbage-collection-algorithms-3869b7b0aa6f

 

2. GC 종류

2-1. Serial GC 

  • 싱글 스레드로 동작하는 GC 방식이다.
  • 그만큼 느리고 STW 시간도 다른 GC에 비해 길다.
  • Mark & Sweep & Compact 알고리즘을 사용
  • 보통 실무에서 사용하는 경우는 없고 다만 CPU가 1코어인 경우에만 사용된다.
  • -XX:+UseSerialGC

이미지 출처 - https://mirinae312.github.io/develop/2018/06/04/jvm_gc.html 

 

 

2-2. Parallel GC

  • Parallel GC는 Minor GC를 처리하는 스레드를 여러 개로 늘려 병렬로 처리하여 Serial GC보다 훨씬 빠르게 동작하는 방식이다. ( Old 영역은 아님)
  • Serial GC보다 STW 시간이 훨씬 짧다.
  • Java 8에서 Default GC 이다.
  • -XX:+UseParallelGC

이미지 출처 - https://mirinae312.github.io/develop/2018/06/04/jvm_gc.html 

 

2-3. Parallel Old GC

  • Parallel GC가 Young 영역에 대해서만 멀티스레드 방식을 사용했다면, Parallel Old GC는 Old 영역까지 멀티스레드 방식을 사용한다.
  • -XX:+UseParallelOldGC
  • -XX:+ParallelGCThreads=n 옵션으로 멀티 스레드 개수를 지정할 수 있다.

 

2-4. CMS GC(Concurrent Mark Sweep GC)

  • Stop The World로 자바 어플리케이션이 멈추는 현상을 줄이고자 만든 GC
  • 접근 가능한(Reachable) 객체를 한번에 찾지 않고 나눠서 찾는 방식을 사용한다. (4 단계로 나뉨)

이미지 출처 - https://velog.io/@guswns3371/Garbage-Collector-%EC%A2%85%EB%A5%98

  • Initial Mark : GC Root가 클래스 로더에서 가장 가까운 객체 중 살아있는 객체만 마킹 함 (STW 발생)
  • Concurrent Mark : 참조하는 객체를 따라가면서 지속적으로 마킹 (STW 없음)
  • Remark : Concurrent Mark 단계에서 새로 추가되거나 참조가 끊긴 객체를 다시 한번 확인 (STW 발생)
  • Concurrent Sweep : 참조 되지 않는 객체를 정리(삭제) 함 (STW 없음)

 

 

2-5. G1GC (Garbage First GC)

  • Java 9+ 에서 Default GC (Oracle JDK 7 update 4 이상 릴리즈에서 지원은 가능)
  • 현재 GC 중 STW의 시간이 제일 짧다.
  • CMS GC를 개선하여 만든 GC로 리전 형식의 구조를 갖는다.

이미지 출처 - https://mirinae312.github.io/develop/2018/06/04/jvm_gc.html 

  • 앞에 나왔던 GC들과는 다르게 Eden, Survivor, Old 영역이 고정된 크기가 아니며 전체 힙 메모리 영역을 Region이라는 특정한 크기로 나눈다.
  • Region의 상태에 따라 그 Region의 역할(Eden, Survivor, Old)가 동적으로 변동한다.
  • Region은 기본적으로 ( 전체 힙메모리 / 2048 )로 지정된다.

 

3. G1G1 Tuning 포인트

G1 GC은 많은 파라미터가 존재하기 때문에 여기서는 가장 일반적으로 권장하는 Tuning 옵션을 몇 가지 적어보려고 한다.

 

1. Maximum GC Pause Time

-XX:MaxGCPauseMillis 설정을 통해 GC 실행 중에 최대 일시 중지 시간을 지정함으로써 높은 지연 시간을 최소화 하거나 높은 처리량을 설정할 수 있다.

 

2. Young Gen 사이즈 세팅을 하지 말 것(-XX:MaxGcPauseMillis 설정을 할 경우)

-Xmn이나 -XX:NewRatio 설정을 피해야 한다. G1GC 알고리즘은 일시 중지 목표 시간을 충족하기 위해 Young 영역을 임의로 수정하게 되는데 Young 영역을 명시적으로 설정할 경우 일시 중지 목표 설정이 정상적으로 작동하지 않는다.

 

3. 다른 GC 알고리즘에서 사용하던 JVM 인수 제거

기본적으로 G1GC의 경우 다른 GC 알고리즘(Serial, Parallel, CMS)에서 사용하던 JVM 인수와 같이 사용할 경우 G1GC의 파라미터가 정상적으로 동작하지 않을 수 있다.

 

4. 문자열 중복 제거

-XX:+UseStringDeduplication 설정을 통해 문자열 중복을 제거 한다.

(최근 연구에 따르면 응용 프로그램 메모리의 13.5%에 중복 문자열이 포함되어 있다고 한다.)

 

5. 이외에 다른 주요 파라미터

G1G1 argument Description
-XX:MaxGCPauseMillis=200 최대 일시 정지 시간 설정 (default : 200ms)
-XX:G1HeapRegionSize=n G1 Region의 크기 설정 (해당 값은 2의 거듭제곱 이어야함 ex)256, 512, 1024..) 
* 범위는 1MB - 32MB
-XX:GCTimeRatio=12 GC에 소요되는 총 목표 시간과 고객 트랜잭션 처리에 소요되는 총 시간을 설정
목표 GC 시간을 결정하는 공식은 [ 1 / (1 + GCTimeRatio) ]로 default 값 12로 대입하여 보면 [ 1 / (1 + 12) ]이므로 7.69%이다. 이 말은 JVM은 전체 시간의 7.69%를 GC 활동에 사용하고 나머지 92.3%는 고객 트래잭션 처리를 하는데 사용하게 된다.
-XX:ParallelGCThreads=n Stop The World의 작업 GC 스레드 수를 설정
논리 프로세서가 8개 이하이면 n값을 논리 프로세서 수로 설정하고 8개 이상이면 n 값을 논리 프로세서 개수의 약 5/8로 설정 한다. 
-XX:ConcGCThreads=n 병렬 마킹 스레드 수를 설정
보통 ParallelGCThreads 수의 1/4로 설정한다.
-XX:InitiatingHeapOccupancyPercent=45 힙 사용량이 백분율을 초과할 때 GC 표시 주기가 트리거 된다. 기본값은 45%
-XX:G1NewSizePercent=5 Young 영역 크기의 최소 값으로 사용할 힙의 백분율 설정
기본 값은 힙의 5%
-XX:G1MaxNewSizePercent=60 Young 영역의 크기의 최대 값으로 사용할 힙의 백분율 설정
기본 값은 힙의 60%
-XX:G1ReservePercent=10 사용 가능한 상태로 유지할 예약 메모리의 백분율 설정
기본 값은 10%
G1GC는 힙의 10%를 항상 사용 가능하도록 하는 것

 

728x90