https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html
https://johngrib.github.io/wiki/java-g1gc/
가장 일반적인 JVM 중 하나로써, 말 그대로 Hot한 Spot을 찾아서 해당 부분에서는 JIT 컴파일러를 사용하는 방법이다.
내부적으로 프로파일링을 통해 핫스팟을 찾아내고, 해당 부분에 대한 네이티브 코드를 생성한다. 이 때 Client 혹은 Server 라인 두 가지 방법 중 하나를 사용한다.
Java 어플리케이션의 실행 중 최적화를 위한 결정을 내리고 기본 시스템 아키텍처를 대상으로 하는 고성능 native machine 명령을 제공한다.
주요 구성 요소에는 Class Loader, Runtime data areas, Execution engine이 포함된다.
성능 튜닝의 중점이 되는 3가지 요소는 Heap, GC, JIT 컴파일러이다.
Heap은 오브젝트 데이터가 저장되는 곳으로써 어플리케이션 시작 시 선택된 GC에 의해 관리된다. 대부분의 튜닝 옵션은 힙의 크기를 조정하는 것과 적절한 GC를 선택하는 것과 관련된다.
JIT 컴파일러도 성능에 큰 영향을 미치나 최신 버전의 JVM에서는 조정할 필요가 거의 없다.
일반적으로 Java 어플리케이션 튜닝 시 목표는 응답성(responsiveness)이나 처리량(throughput) 중 하나라고 할 수 있다.
어플리케이션이나 시스템이 요청된 데이터에 얼마나 빨리 응답하느냐를 나타낸다. 이에 중점을 둔 어플리케이션의 경우 긴 일시 중지 시간이 허용되지 않는다. 즉, 단기간에 대응하는 것에 중점을 둔다.
특정 기간 동안 어플리케이션의 작업량을 최대화하는 것에 중점을 둔다. 이에 중점을 둔 어플리케이션의 경우 긴 일시 중지 시간이 허용된다. 더 긴 시간 동안 벤치마크하는 것에 초점을 두기 때문에 빠른 응답 시간을 고려 사항이 아니다.
❗️ Full GC란
메모리 전체를 대상으로 하는 GC.
Old 영역이 가득차면 Full GC가 발생한다.
Type | Paralle | Concurrent | Young GC | Tenured GC | Feature |
---|---|---|---|---|---|
Serial GC | - | - | Serial | Serial | Batch processing |
Parallel GC | Yes | - | Parallel | Parallel | High throughput |
CMS GC | Yes | Yes | Parallel | Parallel & Conc. | Low Pause |
G1 GC | Yes | Yes | Parallel | Parallel & Conc. | Low Pause & High throughput |
Garbage-First(G1) 컬렉터는 대용량 메모리가 있는 다중 프로세서 시스템을 대상으로 하는 서버-스타일 가비지 컬렉터이다.
-XX:+UseG1GC
옵션을 사용하여 수동으로 활성화할 수 있다.이전 GC와 비교했을 때, 고정된 메모리 크기의 Young Generation, Old Generation, Permanent Generation 으로 구분됐던 것과 달리 아래와 같이 동일한 크기의 힙 영역(Region) 집합으로 분할한다.
JVM 힙은 2048개의 Region으로 나뉠 수 있으며, 각 Region의 크기는 1MB ~ 32MB 사이로 지정될 수 있다. (-XX:G1HeapResionSize 옵션)
추가적으로 Humongous, Available/Unused 라는 영역이 존재한다.
G1은 회수 가능한 영역, 즉 쓰레기가 많을 것으로 예상되는 영역에 대한 수집 및 압축이 주가 된다. 이것이 Garbage-First, G1으로 명명된 이유라고 할 수 있다.
G1은 힙의 하나 이상의 Region에서 단일 Region으로 개체를 복사하고 이 과정에서 메모리를 압축 및 해제 시킨다. 이 때 STW 시간을 줄이고 처리량을 늘리기 위해 다중 프로세서에서 병렬로 작동된다.
reference를 가진 Object등이 어느 Region에 있는지 알기 위해 사용하는 자료구조
주어진 Region에 대한 참조 개체를 추적한다. 각 Region 당 하나의 RSet이 존재하며 이를 통해 Region의 병렬 및 독립된 수집을 가능하게 한다. RSet이 전체 영역에서 차지하는 비율은 5% 이내이다.
GC 로그에서 이 Reference 정보를 갱신(update)하고 검색하는데 소요되는 시간을 확인 할 수 있다.
객체 참조의 Origin을 왜 알아야하는 지는 Baker's Incremental GC 알고리즘, Baker's Incremental Copying Collector 알고리즘 을 참고하자. Reference를 가진 Object를 찾아 라이브 객체를 복사하는 알고리즘이다.
GC가 수행될 Region 집합
CSet 내의 데이터는 GC 동안 모두 비워진다(복사되거나 이동됨). Region 집합은 Eden, Survivor, Old Generation으로 이루어질 수 있다. CSet이 JVM에서 차지하는 비율은 1% 이내이다.
GC 로그에서 CSet을 선택하고 Processing 후 CSet을 해제하는데 걸린 시간을 확인할 수 있다. Evacuation Pauses와 Mixed GC를 수행할 때 사용하는 자료구조이다.
G1 GC에서 Full GC 가 수행될 때는 Initial Mark -> Root Region Scan -> Concurrent Mark -> Remark -> Cleanup -> Copy 단계를 거치게된다.
추가적으로, G1GC는 일시 정지 시간을 줄이기 위해 병렬로 GC 작업을 한다. 각 스레드가 자신만의 region을 잡고 작업하는 방식.
❗️ G1GC의 마킹
SATB(Snapshot-At-The-Beginning) 알고리즘을 사용해 마킹 작업을 한다.
일시 정지가 일어난 시점 직후의 라이브 객체(스냅샷)에만 마킹을 하므로, 마킹 도중 죽은 객체도 라이브 객체로 간주된다. Remark 단계의 응답 시간이 다른 GC에 비해 더 빠른 경향이 있다.
G1은 두 페이즈를 번갈아가며 GC 작업을 한다.
사이클의 흐름은 아래와 같다.
❗️ 어플리케이션 메모리가 부족한 경우 다른 GC와 마찬가지로 Full GC를 수행한다.
Young/Old 영역을 모두 GC 하는 것을 의미한다. Evacaution 때 수행되는 단계와 동일하다. 즉, Evacation Pauses인데 Old Refion이 추가적으로 포함되어 있는 것이다. (Mixed GC = Evacuation Pauses(Young GC + Old GC))
기본적으로 8회 수행되도록 되어있으나 한번에 Garbage를 정리하기엔 Cost가 매우 비싸므로 1회에 모든 Old Region GC가 일어나지는 않는다.
minor GC와 동일하게 Eden/Survivor 영역 크기는 변경될 수 있다.
Mixed GC에 선택되는 CSet은 -XX:G1MixedGCCountTarget
, -XX:G1OldCSetRegionThresholdPercent
에 영향을 받는다. (Old 영역에 관한 CSet Tuning과 관련됨)
Mixed GC 선택 대상 결정은 -XX:G1MixedGCLiveThresholdPercent, -XX:G1HeapWastePercent
에 영향을 받는다.
"Old Region 에 존재하는 객체들이 참조하는 Survivor Region 을 찾는다" 이부분 설명이 잘못되지 않았을까요?