본문 바로가기
dev/java

Generational ZGC in Java 21

by igooo 2024. 7. 2.
728x90

개요

Java 21은 2023 년 9월에 Generational ZGC의 도입과 함께 공개되었다. Highly scalable, low-latency GC 였던 ZGC는 https://openjdk.org/jeps/439를 통해 generational GC로 업데이트 되었다. 이 업데이트에서는 young / old 객체에 대하여 별도의 세대를 도입하여 메모리 관리를 최적화 하는것에 중점을 두었다.

 

What is ZGC?

ZGC는 최대 16TB 크기의 힙을 지원하면서도 밀리초 미만의 일시 정지 시간을 유지하며 높은 확장성을 갖도록 설계되었다. ZGC는 애플리케이션이 실행되는 동안 새로운 객체를 할당하고, 도달할 수 없는 객체를(unreachable object) 스캔하고, 힙을 압축하는 등의 작업을 수행하는데, 이러한 디자인 선택의 단점은 애플리케이션이 사용할 수 있는 CPU 리소스를 ZGC에 사용되기 때문에 애플리케이션 처리량이 줄어든다는 단점이 있었다. 또한 세대를 구분하지 않는 (non-generational) 접근 방식으로 모든 객체를 구분하지 않고 함께 저장함으로 각 GC 주기에 모든 객체를 수집하는 단점이 있다.

 

What is Generational ZGC?

Generational GC는 논리적으로 Heap을 young, old 두 세대로 나눈다. 객체가 할당되면 처음에는 young generation에 배치 되고, young genernation은 자주 스캔된다. 객체가 충분히 오래 지속되면 old generation으로 승격된다(promoted).
Generational GC는 weak-generational hypothesis을(대부분의 객체는 생성 직후에 접근할 수 없게 된다.) 이용하기 위해 위와 같은 동작을 수행한다. 따라서 ZGC는 young generataion을 자주 스캔하여 CPU 리소스를 더욱 효율적으로 활용할 수 있다.


처리량 측면에서는 Generational ZGC는 JDK17의 ZGC보다 10%향상되었고, JDK21의 2GC보다는 10%가 조금 넘게 향 상되었다.

 

하지만 실제 수치를 확인해보면 불가 2~3 마이크로초에 불가하다는 것을 알 수 있다.

ZGC는 최대 일시 정지 시간을 보면 매우 많은 향상이 있다. 아래 차트는 P99일시 정지 시간이 10~20% 향상 이 있음을 보여준다.

 

Using ZGC

ZGC에서 Young / Old Generation을 구분하는 로직은 큰 변경사항이었기 때문에 ZGC팀은 Generational ZGC로의 전환 기간을 설정했다. JDK 21에서 Generational ZGC를 사용하기 위해서는 아래와 같이 두 가지 JVM 옵션 설정이 필요하다. -xx: +ZGenerational 을 설정하지 않으면 기존 ZGC를 사용한다. Generational ZGC는 향후 Java 릴리즈에서 기본 ZGC가 될 예정이다.

$ java -XX:+useZGC -xx:+ZGenerational

 

 

Tuning ZGC

대부분의 사용자가 설정해야 하는 유일한 설정은 최대힙(-Xmx<size>) 설정이지만 추가적으로 아래 설정을 고려할 수 있다.

  • -XXSoftiMaxHeapSize=<size>SoftMaxHeapSize . ZGC가 유지하려고 하는 힙 크기에 대한 가이드라인을 제공한다.
  • -Xms : 최소 힙 크기를 mas heap-Xmx와 동일한 사이즈로 설정한다. 이렇게 하면 ZGC가 요청하지 않는 메모리를 OS에 반환하지 못하게되어 대기 시간이 발생할 수 있다.
  • -XX:ZUncommit: OS로의 메모리 반환을 비활성화할 수 있다. ZGC는 힙 크기가 지정된 최소 힙 크기(-Xms) 아래로 떨어지는 한 메모리가 커밋되지 않도록 보장한다. 따라서 최소 힙 크기가 최대 힙 크기(-Xmx)와 일치하도록 설정된 경우 커밋 해제 기능이 암묵적으로 비활성화 된다.
  • -XX:ZUncommitDelay=<seconds>: ZGC가 OS에 메모리를 반환하기 전에 얼마나 대기할지를 설정한다. (default 300s)
  • -XX+AlwaysPreTouch : 힙 준비가 시작 중으로 이동한다. 이렇게하면 시작 시간이 약간 더 느려지지만 평균 지연 시 간이 줄어드는 이점이 있다.
애플리케이션이 실행되는 동안 ZGC가 메모리를 커밋하고 커밋 해제하도록 허용하면 잠재적으로 애플리케이션의 응답 시간에 영향을 미칠 수 있다. ZGC를 사용할 때 매우 낮은 대기 시간을 달성하는 것이 주요 목표인 경우 최대 힙 크기(-Xmx)와 최소 힙 크기(-Xms)에 동일한 값을 설정하는 것이 좋다. 또한 -XX:+AlwaysPreTouch 옵션을 사용하면 애플리케이션이 시작되기 전에 메모리를 사전 페이지하여 성능을 최적화하고 대기 시간을 줄일 수 있다.

 

 

참고

 

'dev > java' 카테고리의 다른 글

Java 23 : Structured Concurrency  (0) 2024.09.28
Java - ReentrantLock  (0) 2024.07.19
Java Virtual Threads 사용 시 synchronized 주의  (0) 2024.06.04
Virtual Threads  (0) 2024.06.02
java rsa 기반의 암호화  (0) 2016.01.04