https://www.oracle.com/technical-resources/articles/java/g1gc.html
Initiating Heap Occupancy Percent : 최초 마킹 발동 기준이 되는 값, old gen 사이즈에 대한 백분율이다.
Adaptive IHOP
-XX:-G1UseAdaptiveIHOP
옵션으로 on/off가 가능하다.-XX:InitiatingHeapOccupancyPercent
옵션을 주는 경우, 통계값이 충분하지 않은 초기 상태에서 해당 값을 초기값으로 사용한다.-XX:InitiatingHeapOccupancyPercent
로 지정한 IHOP 값을 계속 사용한다.-XX:G1HeapReservePercent
로 설정된 값 만큼의 버퍼를 제외하고 시작 Heap 점유율을 설정한다.-XX:G1HeapReservePercent
값을 뺀 크기가 된 경우 space-reclamation phase의 첫 mixed GC가 시작되도록 하기 위함이다.-XX:G1HeapRegionSize
의 영향을 받는다. 기본값을 사용하고 있다면, 알아서 자동으로 결정된다.-XX:InitiatingHeapOccupancyPercent=45
, -XX:+G1UseAdaptiveIHOP
-XX:G1HeapWastePercent=10
-XX:G1MixedGCCountTarget=8
-XX:MaxGCPauseMillis
값으로 제한된 시간 내에 처리되어야 한다. 처리 불가한 경우 MaxGCPauseMillis
플래그가 우선된다.-XX:G1MixedGCLiveThresholdPercent=85
-XX:MaxGCPauseMillis=200
-XX:GCPauseTimeInterval=<ergo>
-XX:ParallelGCThreads = <ergo>
-XX:HeapSizePerGCThread
옵션으로 지정된 GC 스레드가 담당할 heap 사이즈의 최대값에 영향을 받는다.-XX:ConcGCThreads=<ergo>
-XX:G1HeapRegionSize=<ergo>
XX:G1NewSizePercent=5
, -XX:G1MaxNewSizePercent=60
가장 일반적인 권장 사항은 기본 설정으로 G1을 사용하면서, 적절한 일시 중지 시간 목표를 설정하고 필요한 경우 -Xmx
옵션을 통해 최대 Java 힙 크기를 설정하는 것이다.
❗️ 기본 구성에서 G1의 목표는 높은 처리량에 비해 비교적 적고 균일한 일시 중지를 제공하는 것이다.
-XX:MaxGcPauseMillis
옵션(최대 일시 정지 시간 목표값) 혹은 더 큰 힙을 사용하게 함으로써 일시 중지 시간 목표를 완화해야한다. (일시 중지 시간이 길어질 것)주의 사항
-Xmn
, -XX:NewRatio
등과 같은 옵션을 사용해 young gen.의 크기를 특정 값으로 제한해서는 안된다.일반적으로 다른 수집기(특히 Concurrent-Mark-Sweep GC)에서 G1으로 이동할 때는
-Xmx
, -Xms(optional)
를 사용해 전체 힙 크기만 설정한다.이는 다른 수집기에 영향을 미치는 옵션들은 G1에 영향이 없거나, G1의 처리량과 일시중지 목표를 충족함에 있어 문제를 일으킬 수 있기 때문이다.
G1은 추가 옵션 지정없이도 전반적으로 우수한 성능을 제공할 수 있도록 설계되었다.
하지만, 기본 heuristics(휴리스틱, 추론)이나 구성이 차선의 결과를 제공하는 경우가 있기에 이를 진단하고 개선할 수 있는 몇 가지 방법을 제공한다.
진단을 위해 G1은 포괄적인 로깅을 제공한다. -Xlog:gc*=debug
옵션을 우선 사용하고, 필요한 경우 출력을 상세 조정할 수 있다. 로그는 GC 활동 및 그 외의 다양한 개요를 제공한다. (수집 유형 및 일시 중지의 특정 단계에서 분류별로 소요된 시간 등이 포함된다.)
Full GC는 일반적으로 오랜 시간이 소요된다.
Pause Full(Allocation Failure)
로 표시된다.to-space exhausted
태그로 표시되는 evacuation 실패가 선행된다.Full GC가 발생하는 이유는 (1) 어플리케이션이 신속하게 회수 가능한 수 이상으로 객체를 너무 많이 할당했기 때문이다. 종종 Concurrent marking을 끝내지 못하고 급히 "space-reclamation" 페이즈를 시작하는 경우가 있다.
(2) 또한 G1의 할당 방식 때문에 다수의 큰 객체가 할당될 때, 예상보다 더 큰 메모리를 차지하게 됨으로써 Full GC가 발생활 확률은 더욱 복잡해질 수 있다.
👉 해결책
👉 사용가능한 옵션
1) Heap region 사이즈 조정
gc_heap=info
로깅옵션 : Java 힙에서 큰 객체가 차지하는 region 수를 확인한다. (Humongous Region)Humongous region: X->Y
의 Y는 큰 객체가 차지하는 영역의 양을 나타낸다. 이 값이 old region 보다 크다면 이 객체(humongous region에 포함된 큰 객체)의 수를 줄이는 것이 베스트이다. -XX:G1HeapRegionSize
옵션을 사용해 각 region의 크기를 늘리면 기존 humongous region에 들어갈 수 밖에 없었던 객체가 일반 young region(eden)에 포함될 수 있다.2) Java Heap 크기를 조정
-XX:G1HeapRegionSize
를 명시하지 않는 경우, 각 Region size는 전체 Heap size에 의존하므로 결과적으로 1)안과 동일하다.3) 명시적으로 -XX:ConcGCThreads
옵션을 설정해 Concurrent marking에 사용되는 thread 수를 증가시킨다.
4) G1이 더 일찍 마킹하도록 한다.
-XX:+G1UseAdaptiveIHOP
옵션을 사용해 이전 어플리케이션 동작을 기반으로 IHOP 임계값을 결정하므로 어플리케이션 동작이 변경되는 경우 예측이 틀릴 수 있다.-XX:G1ReservePercent
를 사용해 adaptive IHOP 계산에 사용되는 버퍼를 증가시킴으로써 "space-reclamation"을 시작할 시점에 대한 목표치를 낮춘다.-XX:-G1UseAdaptiveIHOP
및 -XX:InitiatingHeapOccupancyPercent
를 사용해 수동으로 adaptive IHOP 계산을 비활성화 시킬 수 있다.Full GC에 대한 할당 실패 외에 어플리케이션 혹은 일부 외부 도구에 의해 Full heap collection이 유발되는 경우가 있을 수 있다.
System.gc()
에 의해 발생하나 어플리케이션 코드를 수정할 방법이 없는 경우, -XX:+ExplicitGCInvokesConcurrent
를 사용해 Full GC의 영향을 감소시키거나 -XX:+DisableExplicitGC
설정으로 VM이 이를 무시하도록 할 수 있다.
❗️NOTE 대형 객체에 의한 문제
-XX:G1HeapRegionSize
을 사용해 대형 객체의 수를 조절할 수 있다.
하지만 극단적인 경우, G1이 객체를 할당하는데 필요한 연속 공간이 불충분 할 수 있다. Full GC를 통해 충분한 연속 Region을 회수할 수 없는 경우 VM은 종료된다.가능한 방법은 humongous 객체 할당량을 줄리거나 heap size를 늘리는 수 뿐이다.
일시 중지 시간이 너무 긴 경우
1) 비정상적인 시스템 혹은 Real-Time 어플리케이션
로그에서는 일시 중지 시간이 어디서 사용되었는지에 대한 분석을 확인 할 수 있다.
시스템 시간이 상대적으로 높은 경우 대부분 환경이 원인이다. 이런 경우 아래와 같은 조치를 취할 수 있다.
-Xms
, -Xmx
옵션을 사용해 최소/최대 힙 크기를 동일한 값으로 설정-XX:+AlwaysPreTouch
옵션을 사용해 모든 메모리를 미리 할당/반환 시킨다.2) Real 시간이 User와 System 시간을 합친 것보다 큰 경우
3) Reference Object 처리 시간이 너무 오래 걸리는 경우
-XX:ParallelGCThreads
값을 기준으로하여 싱글 스레드로 작동한다.-XX:ReferencesPerThread
를 0으로 설정하거나 -XX:-ParallelRefProcEnabled
로 병렬화를 비활성화 할 수 있다.4) Young-Only 단계에서 Young-Only Collection 시간이 오래걸리는 경우
일반적으로 Young Colelction은 Young Gen.의 크기. 즉, 복사가 진행될 CSet 내 라이브 객체 수에 비례하는 시간이 소요된다.
-XX:G1NewSizePercent
를 작게 설정해 Young gen.의 최소 크기를 줄여준다.-XX:G1MaxNewSizePercent
를 작게 설정해 Young gen.의 최대 크기를 줄여준다.5) Mixed Collection 시간이 오래걸리는 경우
Mixed Collection은 Old gen. Region을 회수하는데에 사용된다. 즉 Mixed Collection에는 Young gen.과 Old gen. Region이 모두 포함된다.
로그 출력 시 gc+ergo+cset=trace
를 활성화하여 관련된 정보를 얻을 수 있다.
Old gen. 시간이 긴 경우
-XX:G1MixedGCCountTarget
을 높게 설정해 Old gen내 Region 처리 개수를 늘린다.-XX:G1MixedGCLiveThresholdPercent
를 사용해 GC 대상을 줄인다.-XX:G1HeapWastePercent
값을 높게 설정해 G1이 높은 메모리를 차지하는 Region은 수집하지 않도록 한다.Young Gen. 시간이 긴 경우 (4)를 참조하도록 한다.
6) RSet 업데이트 및 스캔 시간이 긴 경우
G1은 단일 Old gen region을 피하기 위해 cross-region references의 위치를 추적한다. (한 region에서 다른 region를 참조) 이를 해당 region의 Reference set(RSet)이라고 부른다.
Region 내용이 이동될 때(Evacuation), RSet은 업데이트된다. 단, 이는 효율을 위해 즉시 업데이트되지 않고 일괄 처리된다. 이 때 어플리케이션에 따라 상당한 시간이 소요될 수 있다.
-XX:G1HeapRegionSize
로 heap region의 크기를 조정-XX:G1RSetUpdatingPauseTimePercent
로 RSet update에 사용되는 시간을 강제화 할 수 있다.RSet을 스캔하는 시간은 G1이 메모리에 저장되는 RSet storage 크기를 작게 유지하기 위해 수행하는 압축정도에 의해 결정된다. 즉, RSet이 더욱 작게 (압축되어) 저장될수록 값을 검색하는데에 더 많은 시간이 걸린다.
gc+remset=trace
수준의 로깅과 함께 -XX:G1SummarizeRSetStatsPeriod
옵션을 사용할 시 이러한 압축이 발생하는지 확인 할 수 있다. ([Before GC Summary] 섹션 이전 Did <X> coarsenings
라인의 X값은 높은 값을 보여줄 것이다.)
-XX:G1RSetRegionEntries
을 높임으로써 압축되는 양을 감소 시킬 수 있다.G1은 기본적으로 처리량과 대기 시간 간의 균형을 유지하려고 하지만 어플리케이션에 따라 높은 처리량이 바람직한 경우도 있다.
-XX:MaxGCPauseMillis
를 사용해 최대 일시 중지 시간을 늘린다. (일시 중지 빈도는 감소한다.)space-reclamation phase에서 예상되는 동작이 이뤄지지 않는 경우
-XX:G1NewSizePercent
옵션으로 young gen의 최소 크기를 늘리면 된다.
-XX:G1MaxNewSizePercent
로 young gen.의 최대 크기를 늘려 처리량을 증가 시킨다.-XX:G1RSetUpdatingPauseTimePercent
를 높은 값으로 설정하면 동시 작업이 감소, 일시 중지 시간 증가-XX:-G1UseAdaptiveConcRefinement
, -XX:G1ConcRefinementGreenZone=2G
, -XX:G1ConcRefinementThreads=0
-Xms
, -Xmx
를 같은 값으로 설정-XX:+AlwaysPreTouch
를 설정