ZGC
메인 이미지는 https://wiki.openjdk.java.net/display/zgc/Main 에서 가져왔습니다.
최근 ZGC에 대한 질문을 받았으나 대답하지 못해 아쉬웠던 상황이 있었습니다. 완벽하게 이해하고 쓰는 글이 아니라 학습을 위해 정리하는 글이기 때문에 잘못된 내용이 있을 수 있으니 그 점 양해 부탁드립니다.
ZGC
Heap Memory 공간이 커지더라도 S-T-W 시간이 증가하지 않는 특징을 가진 GC이며 각각의 객체를 단일 세대로써 관리되며, 객체들은 G1 GC와 유사한 Region 방식으로 관리된다.
해당 GC는 Java 11부터 Preview로 추가되었으며, 15에서 Production Ready 상태가 되었다.
ZGC의 목표
G1 보다 처리량이 15% 이상 떨어지지 않으면서, S-T-W 시간은 10ms를 초과하지 않는 것.
- S-T-W 가 매우 짧다.
ZGC의 특징
대기 시간이 낮으면서 규모 확장이 가능한 GC이다.
- GC에 관련된 모든 작업을 Application과 동시에 작업한다. (Concurrently)
- CMS나 G1의 경우 Mark 작업의 일부를 Application과 Concurrently 하게 수행한다.
- Application이 수행되는 동안 GC Thread를 여러 개 동작시킬 수 있다.
- 동시 수행 Thread가 적은 경우에는 Garbage가 점점 누적되며 (메모리 누수), Thread가 많은 경우에는 Application의 CPU 수행 시간을 많이 소모함으로 요청 처리량을 떨어트린다.
ZGC Core Concepts
ZGC는 Colored pointers와 Load barriers라는 2가지 주요 요소를 사용한다.
Colored pointers
- ZGC가 객체를 찾아낸 뒤, 마킹하고, 재 배치하는 등의 작업을 지원한다.
- 객체 포인터의 메모리 공간을 활용하여 객체의 상태 값을 저장하고 사용한다.
- 해당 알고리즘 방식은 64bit 메모리 공간을 필요로 하기 때문에 32 bit 기반의 플랫폼에서는 사용이 불가능하다.
- 18 bit의 미 사용 공간, 42 bit의 객체의 참조 주소와 총 4 bit의 공간을 차지하는 4개의 color pointer가 존재한다. 이러한 bit들을 meta bits라고 한다.
- Finalizable : Finalizer(Finalize queue??)을 통해서 참조되는 객체로 해당 pointer가 Mark 되어 있다면 non-live Object이다.
- Remapped : 해당 객체의 재배치 여부를 판단하는 pointer이며, 해당 Bit의 값이 1이라면 최신 참조 상태임을 의미한다.
- Marked 0, Marked 1 : 해당 객체가 Live된 상태 인지 확인하는 여부이다. - Load Barrier에 의해서도 사용되기도 한다.
Load Barriers
- JIT가 특정 위치에 주입한 코드를 말한다. 이 코드를 통해 참조가 연결되는 객체의 Meta bits 상태를 확인한다.
- Load barriers는 RemapMark와 Relocation Set을 확인하여 참조 값과 Mark 상태를 업데이트할 수 있다.
- Load Barriers는 Thread가 Stack으로 Heap Object 참조 값을 불러올 때 실행된다.
Reference Value Check Flow
- mark pointer의 색이 나쁜 경우 mark, relocate, re-mapping을 진행하여 좋은 상태 (색상)로 변경하는 작업을 진행한다. repair or heal
- mark pointer의 색이 좋은 경우 그대로 작업을 진행한다.
- Remap bit가 1인 경우 바로 참조 값을 반환하며 그렇지 않은 경우에는 참조된 개체가 Relocation Set에 있는지 확인한다.
- Set에 없는 경우 Remap bit를 1로 설정한다. (재 배치 되었음을 의미하기에)
- Set에 있는 경우에는 Relocation 하고 forwarding table에 해당 정보를 기록한 뒤 Remap bit를 1로 설정한다.
- 참조 값을 반환한다.
Forwarding table
Relocation 대상인 객체의 현재 참조 값과 변경 후 참조 값을 기록하는 일종의 Mapping Table을 말한다. 이를 이용하여 현재 Relocation 된 객체를 바로 접근하고 참조할 수 있다.
ZGC Flow
ZGC Marking Flow
해당 Flow는 Pause Mark Start → Pause Mark End를 포함한다.
Root Set Mark (S-T-W) :
- 객체를 참조하는 Root set을 찾아 Marking 하는 작업이다. Root Set은 상대적으로 적기 때문에 매우 짧은 S-T-W를 가진다.
Concurrent Mark & Concurrent Remap
- Application과 동시에 수행되는 단계로 Marking 된 Root set으로부터 객체 간의 참조 관계(그래프)를 추적하여 접근한 모든 객체를 Marking 한다. (Marked bit check)
- Load barrier를 활용하여, Marking 되지 않은 Object load를 감지하고 해당 객체의 mark pointer도 표시한다.
Concurrent Prepare & Edge Handle ( Week Reference Clear... S-T-W)
- Local Thread 간의 동기화를 진행한다. Thread local handshakes
- 이후 Week, Phantom Reference와 같은 일부 edge case를 확인하고 정리한다.
ZGC Relocation Flow
해당 Flow는 Pause Relocation Start ~ End를 포함한다.
Concurrent Relocate
- Mark Flow가 끝나고 재배치할 대상을 찾아 Relocation Set에 배치한다.
- Mapping 되지 않은 대상들은 Heap Memory에서 정리한다.
- Relocation Set에 연결된 대상 중 Root Set을 통해 참조되는 모든 객체를 재 배치 후 업데이트한다.
Concurrent Relocation and update
- Relocation Set에 남아있는 대상들을 추적하며 재배치하고 이전 참조 값과 변경된 참조 값을 Mapping 하는 forwarding table에 저장한다.
- Load barrier를 이용하여 Relocation Set에 배치된 대상을 참조하는 Pointer를 감지할 수 있다.
이후 생성되는 참조 관계는 다음 Mark 단계부터 다시 진행된다.