G1GC Garbage Collector에 대해 알아보기 - 2
2023-04-10 20:14
전편에 이어서, G1GC의 목적에 따른 옵션 가이드를 제공합니다. 프로젝트에 최적화 된 GC를 적용해 보세요.
개요
G1GC 의 목적과 옵션별 역할에 대해서 예제와 함께 설명한다.
Details: Option Example
export JAVA_OPTS="$JAVA_OPTS -XX:+UseG1GC"
export JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=100"
export JAVA_OPTS="$JAVA_OPTS -XX:InitiatingHeapOccupancyPercent=10"
export JAVA_OPTS="$JAVA_OPTS -XX:ParallelGCThreads=2"
export JAVA_OPTS="$JAVA_OPTS -XX:ConcGCThreads=2"
-Xms4096m -Xmx4096m -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:InitiatingHeapOccupancyPercent=10 -XX:+UseLargePagesInMetaspace -XX:ParallelGCThreads=8 -XX:ConcGCThreads=8 -Dfile.encoding=UTF-8 -verbose:gc -ea
InitiatingHeapOccupancyPercent
- 통칭 IHOP 이라고 부른다.
- 최초 마킹 발동 기준이 되는 값으로써 Old Generation 사이즈에 대한 백분율이다. 즉, 전체 크기 대비 Heap의 사용 비율이 해당 임계값을 넘어가면 GC가 동작한다.
- default 값은 45. (전체 크기 대비 heap 사용이 45%가 넘어가면 Marking 시작)
- 이 옵션이 낮을수록 Mixed Collection 이 자주 일어나며 Heap 에 대한 GC 와 Compaction 빈도가 많아지게 된다.
- G1GC 가 Old 영역 Compact 및 클린징을 위한 Mixed Collection을 트리거 하는데, 그 기준값이 되는 옵션중에 하나다.
Mixed GC
Full GC를 완료하는 시점에 Young/Old Region을 동시에 GC 한다.
Adaptive IHOP
- 수집한 통계 데이터(마킹 소요 시간 및 주기)를 기반으로 최적의 IHOP 값을 찾아내 자동으로 설정해준다.
-XX:-G1UseAdaptiveIHOP
으로 on/off 한다.- dafault 값은 true.
-XX:InitiatingHeapOccupancyPercent
옵션을 초기값으로 사용한다. (Adaptive IHOP off 시 해당 값을 계속 사용한다.)
Note:
G1 has both concurrent (runs along with application threads, e.g., refinement, marking, cleanup) and parallel (multi-threaded, e.g., stop the world) phases. Full garbage collections are still single threaded, but if tuned properly your applications should avoid full GCs.
ParallelGCThreads
- STW에 동작하는 스레드
- 사용 가능한 프로세서 수가 8보다 작은 경우 지정한 값을 사용하고, 그 외에는 5/8만큼의 스레드를 추가로 사용한다.
- 예) 사용가능한 프로세스 수가 13개 → 8(기본)+(13-8)*(5/8)=11.125 → 11개 사용
- 단, 최대 heap 사이즈에 의해 제한을 받는다.
ConGCThreads
- 애플리케이션이 여러 페이즈와 함께 동작할때 사용하는 스레드.
-XX:ParallelGCThreads
를 4로 나눈 값이다.
Number of threads concurrent garbage collectors will use. The default value varies with the platform on which the JVM is running.
MaxGCPauseMillis
- 최대 일시 정지 목표 시간.
- default는 200ms.
- 이는 반드시 보장하는 값은 아니며, Full GC 시에는 해당되지 않는다.
UseLargePagesInMetaspace
- Jdk8 이후부터 Perm영역이 아니라 MetaSpace에 클래스 정보를 올리는데, 이 영역이 크면 GC 소요시간이 크다. 이때 이 옵션을 사용해야 언로딩에 의한 Pause 타임을 줄일수 있다.
G1ReservePercent
- 여유 공간을 유지하기 위한 메모리 공간에 대한 백분율이다.
- default는 10.
- GC 이후 Old 영역 승급시 할당된 공간이 없으면 실패가 나는 경우를 줄이기 위해 미리 heap 공간을 확보한다.
- 실패로 인해 발생하는 일련의 이벤트의 시간 비용이 매우 크기 때문에 이를 방지하기 위한 옵션.
G1HeapRegionSize
- Region 사이즈 비율, 가급적 기본값을 사용하는 것을 권장.
- default는 최대 heap 사이즈의 1/2048.
- 설정 가능 사이즈는 1 ~ 32MB 정도이며, 반드시 2의 거듭제곱 값이어야 한다.
G1HeapWastePercent
- 얼마나 많은 region이 낭비되어도 괜찮은지 결정한다. 즉, Heap이 낭비해도 좋다고 판단하는 값이다.
- Mixed cycle의 종료 시점을 결정한다.
- default는 10.
- Mixed Collection 이후 Old Region의 Reclaim 후보군이 해당 임계점보다 낮을경우 Skip하게 된다.
G1MixedGCCountTarget
- 1회 Mixed GC 때 처리할 Region의 개수.
- default는 8.
- 값이 작을수록 Mixed GC가 여러 주기에 거쳐 가비지를 수거한다. 회당 일시 중지 시간은 증가하나 전체로 봤을 때는 빠르게 Region을 비울 수 있음.
- Mixed Collection은 G1HeapWastePercent 임계값보다 낮추기 위한 사이클로 수행하는데, 이는 예측 가능한 Pause Time 에 맞게 수행하기 위함이다.
G1MixedGCLiveThresholdPercent
- Old Region 내 라이브 객체의 점유율이 해당 옵션보다 높다면 GC 대상에서 제외된다. (Space-Reclamation 단계에서 수집되지 않는다.)
- 다시 말해 Old Region에 임계값보다 많은 오브젝트들이 사용중이면 Old 영역 Reclaim 이 일어나지 않는다.
- default 값은 85.
- 이 상황에서 Survior to Old 로 프로모션이 계속 일어나는 경우 할당 공간이 더이상 없어 Full GC가 발생한다.
Details: Option 튜닝
JDK 8부터 PermGen 영역이 사라지고 Metaspace영역으로 대체되었다. 크기를 제한하던 이전과 달리 OS native 메모리를 사용 할 수 있다.
G1GC의 목표는 높은 처리량에 비해 비교적 적고 균일한 일시 중지 시간(STW)를 제공하는 것이다.
높은 처리량
-XX:MaxGcPauseMillis
(최대 일시 정지 시간) 증가 혹은 힙 크기 확장을 통해 일시 중지 시간을 길게 만들어 준다.
지연 시간 최소화
-XX:MaxGcPauseMillis
(최대 일시 정지 시간) 감소
단, Young Generation은 설정된 일시 중지 시간을 충족 할 수 있도록 만드는 주요 수단이므로, -Xmn
, -XX:NewRatio
등의 옵션을 사용해 Young Generation의 크기를 특정 값으로 강제하지 않도록 한다.
Details: 성능 향상
기본적으로 G1은 추가 옵션 지정없이도 전반적으로 우수한 성능을 제공할 수 있도록 설계되었다. 하지만 기본 휴리스틱(hueuristics, 추론)이나 구성이 차선의 결과를 제공하는 경우가 있으므로, 이를 진단하고 개선할 수 있는 몇 가지 방법을 가이드 해주고 있다.
Full GC
old generation의 높은 힙 점유율로 인한 Full GC는 로그에서 Pause Full(Allocation Failure)로 표시된다.
일반적으로 to-space exhausted 태그로 표시되는 evacuation 실패가 선행된다.
Full GC가 발생하는 이유는 일반적으로 다음과 같다.
- 애플리케이션이 신속하게 회수 가능한 수 이상으로 객체를 너무 많이 할당한 경우 → Concurrent marking을 마치지 못하고 급하게 space-reclamation phase를 시작하게 됨
- G1 할당 방식에 의해 다수의 큰 객체가 할당된 경우 → 예상보다 더 큰 메모리를 차지하게 됨으로써 발생
Concurrent marking이 목표 시간에 종료 될 수 있도록 조정해 줌으로써 개선이 가능하다.
- old generation의 할당 비율을 줄인다.
- Concurrent marking을 완료할 수 있을 때까지 충분한 시간을 제공한다.
다음 옵션들을 적용해 봄으로써 개선한다.
- Heap region 사이즈 조정
-XX:G1HeapRegionSize
증가: 객체 크기가 커서 humongous region에 들어갈 수 밖에 없던 객체를 young region에 들어 갈 수 있게 만든다.- 극단적인 경우, 객체 할당에 필요한 연속 공간이 불충분 할 수 있다. Full GC로 연속 region을 회수 할 수 없는 경우 VM이 종료되어버리는 문제가 발생한다. 이런 경우 humongous 객체 할당량을 감소시키거나 heap size를 늘리는 방법 뿐이다.
- Java heap 사이즈 조정
-XX:G1HeapRegionSize
를 명시하지 않는 경우. region size는 전체 heap size에 의존하므로 1과 동일한 효과를 가짐- 단, 마킹 시 사용되는 시간이 증가하는 문제가 생길 수 있다.
- Concurrent marking에 사용되는 thread 수 조정
-XX:ConcGCThreads
증가
- 마킹하는 시점을 당김(GC가 더 자주 일어나도록 한다.)
-XX:G1ReservePercent
증가: (Adaptive IHOP 계산에 사용되는 버퍼 증가) space-reclamation을 시작할 시점에 대한 목표치를 낮춘다.-XX:-G1UseAdaptiveIHOP=false
,-XX:InitiatingHeapOccupancyPercent
설정: Adaptive IHOP 계산을 비활성화 시킨다.
- 외부 문제에 의한 유발 최소화
-XX:+ExplicitGCInvokesConcurrent
설정 : Full GC의 영향을 감소시킨다.-XX:+DisableExplicitGC
설정
지연시간 조정
로그에서는 일시 중지 시간 동안 어떻게 시간을 보냈는지 알 수 있다.
- User Time : VM 코드에서 보낸 시간
- System Time : OS에서 보낸 시간
- Real Time : 일시 중지 중 경과된 절대(absolute) 시간
다음 상황별 해결책들을 적용해 보자.
- System Time(OS)에서 보낸 시간이 상대적으로 높은 경우, 대부분 환경이 원인이다.
- VM이 OS 메모리로부터 메모리를 할당하거나 반환하는 경우
-Xms
,-Xmx
: 최소/최대 힙 크기를 동일하게 설정한다.-XX:+AlwaysPreTouch
: 해당 작업을 VM시작단계로 이동시킨다. 즉, 미리 메모리를 할당/반환시킨다.
- Linux의 THP(Transparent Huge Pages)기능에 의해 작은 Page를 큰 Page로 병합하다가 임의의 프로세스가 중단되는 경우
- OS 설정을 통해 해당 기능을 비활성화 할 필요가 있을 수 있다.
- 로그가 기록되는 하드 디스크의 모든 I/O 대역폭을 간헐적으로 차지하는 일부 백그라운드 작업에 의해 로그 쓰기가 중단되는 경우.
- 로그 작성을 위한 별도의 디스크를 사용하는 것을 추천한다.
- VM이 OS 메모리로부터 메모리를 할당하거나 반환하는 경우
- Real > User + System 인 경우 → VM 과부하 가능성이 있는 시스템에서 충분한 CPU 시간을 얻지 못했음
- Reference Object 처리 시간이 너무 오래 걸리는 경우
- Reference Object는
-XX:ParallelGCThreads
값을 기준으로하여 싱글 스레드로 작동한다. -XX:ReferencesPerThread=0
or-XX:-ParallelRefProcEnabled
(병렬화 비활성화): 사용가능한 모든 스레드를 사용하도록 설정한다.
- Reference Object는
- Young-Only 단계에서 Young-Only Collection 시간이 오래걸리는 경우
- Young Collection은 CSet 내 라이브 객체 수에 비례하는 시간이 소요된다.
- CSet의 Evacuate 단계, 특히 sub-phase인 객체 복사 시간이 지연되는 경우
-XX:G1NewSizePercent
감소: Young generation의 최소 크기를 줄인다.
- 애플리케이션의 성능, 특히 컬렉션에 남아 있는 객체의 양이 급변하는 경우
-XX:G1MaxNewSizePercent
감소: Young generation의 최대 크기를 줄여준다. → 일시 중지 중 처리해야하는 개체 수를 제한
- Mixed Collection 시간이 오래걸리는 경우
- Young Generation에서의 시간이 긴 경우 (4)를 참조한다. 여기서는 Old Generation 처리가 느린 경우만 다룬다.
-XX:G1MixedGCCountTarget
증가: Old generation 내 Region 처리 개수를 늘린다.-XX:G1MixedGCLiveThresholdPercent
감소: GC 대상을 감소시킨다.-XX:G1HeapWastePercent
증가: 높은 메모리를 차지하는 Region은 수집하지 않도록 한다.
- RSet 업데이트 및 스캔 시간이 긴 경우
- Region 내용이 이동될 때(Evacuation) Rset이 업데이트된다. 단, 즉시 업데이트 되지 않고 효율을 위해 일괄 처리된다. 이 때 애플리케이션에 따라 상당한 시간이 소요될 수 있다.
-XX:G1HeapRegionSize
: heap region 크기 조정- cross-region references 수와 RSet의 크기에 영향을 준다.
- region이 클 경우, cross-region references가 적은 경향이 있으므로 상대적으로 처리에 소요되는 작업량이 감소된다. 단, 각 region이 더 많은 라이브 객체를 가지므로 다른 단계의 지연 시간이 증가할 가능성이 있다.
-XX:G1RSetUpdatingPauseTimePercent
: RSet update에 사용되는 시간을 강제화- 해당 옵션값이 작을 수록 G1은 더 많은 RSet 업데이트 작업을 동시에 수행시킨다.
-XX:G1RSetRegionEntries
증가: RSet이 압축되는 양을 감소 시킴으로써 값을 검색하는데에 걸리는 시간을 줄인다.
처리량 조정
높은 처리량을 원하는 경우
-XX:MaxGCPauseMillis
증가: 최대 일시 중지 시간 늘림 (빈도는 감소)-XX:G1MaxNewSizePercent
증가 : young generation 최대 크기 증가 → 처리량 증가- 동시 작업을 위한 RSet 업데이트에 리소스 소모가 크므로 동시 작업량 감소시켜 처리량 증가시킨다.
-XX:G1RSetUpdatingPauseTimePercent
증가 : 동시 작업 감소, 일시 중지 시간 증가-XX:-G1UseAdaptiveConcRefinement
,-XX:G1ConcRefinementGreenZone=2G
,-XX:G1ConcRefinementThreads=0
: 극단적인 방법으로써 RSet 업데이트 비활성화 후 다음 GC로 이월시킬 수 있다.
- heap 사이즈 조정 작업을 끄거나 최소화한다.
-Xms
,-Xmx
를 같은 값으로 설정-XX:+AlwaysPreTouch
를 설정
결론
이번 포스팅은 G1GC Option Guide를 통해 실제 G1GC를 세밀하게 컨트롤하는 방법을 알아보았다. 옵션 조정을 통해 어떤 상황에서든 GC에 있어서는 최상의 성능을 내는 애플리케이션을 설계해 보자.
Ref
- https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html
- https://docs.oracle.com/en/java/javase/11/gctuning/garbage-first-garbage-collector-tuning.html#GUID-4914A8D4-DE41-4250-B68E-816B58D4E278
- https://docs.oracle.com/en/java/javase/11/gctuning/garbage-first-garbage-collector.html#GUID-ED3AB6D3-FD9B-4447-9EDF-983ED2F7A573