1. 소개
JVM은 다양한 배치 옵션을 지원하기 위해 다양한 가비지 콜렉션 옵션과 함께 제공됩니다. 이를 통해 애플리케이션에 사용할 가비지 수집기 를 유연하게 선택할 수 있습니다.
기본적으로 JVM은 호스트 컴퓨터의 클래스에 따라 가장 적합한 가비지 수집기를 선택합니다. 그러나 때때로 우리 응용 프로그램은 사용되는 알고리즘을 더 많이 제어해야 하는 주요 GC 관련 병목 현상을 경험합니다. 문제는 "GC 알고리즘을 어떻게 결정합니까?"입니다.
이 기사에서 우리는 그 질문에 답하려고 시도합니다.
2. GC란 무엇입니까?
Java는 가비지 수집 언어 이므로 응용 프로그램에 수동으로 메모리를 할당하고 할당 해제해야 하는 부담에서 보호됩니다. OS가 JVM 프로세스에 할당한 전체 메모리 청크를 힙 이라고 합니다 . 그런 다음 JVM은 이 힙을 세대라는 두 그룹으로 나눕니다. 이러한 분석을 통해 효율적인 메모리 관리를 위한 다양한 기술을 적용할 수 있습니다.
Young(Eden) 세대 는 새로 생성된 객체가 할당되는 곳 입니다 . 일반적으로 작고(100-500MB) 두 개의 서바이버 공간 이 있습니다. Old Generation 은 오래되거나 오래된 객체가 저장되는 곳입니다 . 이러한 객체는 일반적으로 수명이 긴 객체입니다. 이 공간은 젊은 세대보다 훨씬 큽니다.
수집기는 지속적으로 젊은 세대의 충만도를 추적하고 살아있는 개체가 생존자 공간 중 하나로 이동되고 죽은 개체가 제거되는 동안 마이너 컬렉션을 트리거합니다. 개체가 특정 수의 마이너 GC에서 살아남은 경우 수집기는 해당 개체를 이전 세대로 이동합니다. 이전 공간이 가득 찬 것으로 간주되면 주요 GC가 발생 하고 죽은 개체가 이전 공간에서 제거됩니다.
이러한 각 GC 중에는 아무 일도 일어나지 않는 stop-the-world 단계가 있습니다. 애플리케이션은 어떤 요청도 처리할 수 없습니다. 이 일시 중지 시간 이라고 합니다.
3. 고려해야 할 변수
GC는 수동 메모리 관리로부터 우리를 보호해 주지만 비용을 들여 이를 달성합니다. 우리는 GC 런타임 오버헤드를 가능한 한 낮게 유지하는 것을 목표로 해야 합니다 . 애플리케이션 요구 사항에 가장 적합한 수집기를 결정하는 데 도움이 되는 몇 가지 변수가 있습니다. 이 섹션의 나머지 부분에서 이에 대해 살펴보겠습니다.
3.1. 힙 크기
이것은 OS가 JVM에 할당한 작업 메모리의 총량입니다. 이론적으로 메모리가 클수록 수집 전에 더 많은 객체를 보관할 수 있으므로 GC 시간이 길어집니다 . 최소 및 최대 힙 크기는 -Xms=<n> 및 -Xmx=<m> 명령줄 옵션을 사용하여 설정할 수 있습니다.
3.2. 애플리케이션 데이터 세트 크기
애플리케이션이 효과적으로 작동하기 위해 메모리에 보관해야 하는 개체의 총 크기입니다. 모든 새 개체가 젊은 세대 공간에 로드되기 때문에 이는 최대 힙 크기와 GC 시간에 확실히 영향을 미칩니다.
3.3. CPU 수
머신에서 사용할 수 있는 코어 수입니다. 이 변수는 우리가 선택한 알고리즘에 직접적인 영향을 미칩니다. 일부는 사용 가능한 코어가 여러 개인 경우에만 효율적이며 다른 알고리즘의 경우 그 반대입니다.
3.4. 일시정지 시간
일시 중지 시간 은 가비지 수집기가 메모리를 회수하기 위해 애플리케이션을 중지하는 기간입니다. 이 변수는 대기 시간에 직접적인 영향을 미치므로 목표는 이러한 일시 중지 중 가장 긴 시간을 제한하는 것입니다.
3.5. 처리량
이는 프로세스가 실제로 애플리케이션 작업을 수행하는 데 소비하는 시간을 의미합니다. 애플리케이션 시간 VS GC 작업 수행에 소요되는 오버헤드 시간이 높을수록 애플리케이션 처리량이 높아집니다 .
3.6. 메모리 공간
이것은 GC 프로세스에서 사용하는 작업 메모리입니다. 설정에 제한된 메모리 또는 많은 프로세스가 있는 경우 이 변수가 확장성을 나타낼 수 있습니다.
3.7. 신속성
이것은 객체가 죽은 시점과 점유한 메모리가 회수되는 시점 사이의 시간입니다. 힙 크기와 관련이 있습니다. 이론적으로 힙 크기가 클수록 컬렉션을 트리거하는 데 시간이 오래 걸리므로 신속성이 낮아집니다.
3.8. 자바 버전
새로운 Java 버전이 나오면 일반적으로 지원되는 GC 알고리즘과 기본 수집기도 변경됩니다. 기본 수집기와 기본 인수로 시작하는 것이 좋습니다. 각 인수를 조정하면 선택한 수집기에 따라 다양한 효과가 있습니다.
3.9. 지연 시간
이것은 응용 프로그램의 응답성입니다. GC 일시 중지는 이 변수에 직접 영향을 미칩니다.
4. 가비지 컬렉터
직렬 GC 외에 다른 모든 수집기는 사용 가능한 코어가 둘 이상일 때 가장 효과적입니다.
4.1. 직렬 GC
직렬 수집기는 단일 스레드를 사용하여 모든 가비지 수집 작업을 수행합니다. 특정 소규모 하드웨어 및 운영 체제 구성에서 기본적으로 선택되거나 -XX:+UseSerialGC 옵션을 사용하여 명시적으로 활성화할 수 있습니다 .
장점:
- 스레드 간 통신 오버헤드가 없으면 비교적 효율적입니다.
- 클라이언트급 기계 및 임베디드 시스템에 적합합니다.
- 데이터 세트가 작은 애플리케이션에 적합합니다.
- 다중 프로세서 하드웨어에서도 데이터 세트가 작은 경우(최대 100MB) 여전히 가장 효율적일 수 있습니다.
단점:
- 대규모 데이터 세트가 있는 애플리케이션에는 효율적이지 않습니다.
- 다중 프로세서 하드웨어를 활용할 수 없습니다.
4.2. 병렬/처리량 GC
이 수집기 는 가비지 수집 속도를 높이기 위해 여러 스레드를 사용합니다 . Java 버전 8 및 이전 버전에서는 서버 클래스 머신의 기본값입니다. -XX:+UseParallelGC 옵션 을 사용하여 이 기본값을 재정의할 수 있습니다 .
장점:
- 다중 프로세서 하드웨어를 활용할 수 있습니다.
- 직렬 GC보다 더 큰 데이터 세트에 더 효율적입니다.
- 높은 전체 처리량을 제공합니다.
- 메모리 공간을 최소화하려고 시도합니다.
단점:
- 응용 프로그램은 stop-the-world 작업 중에 긴 일시 중지 시간 이 발생합니다 .
- 힙 크기에 따라 잘 확장되지 않습니다.
배치 작업, 오프라인 작업 및 웹 서버와 같은 비대화형 앱의 경우처럼 더 많은 처리량을 원하고 일시 중지 시간에 신경 쓰지 않는 것이 가장 좋습니다.
장점:
- 일시 중지 시간을 최소화하므로 대기 시간이 짧은 애플리케이션에 적합합니다.
- 힙 크기에 따라 비교적 잘 확장됩니다.
- 다중 프로세서 시스템을 활용할 수 있습니다.
단점:
- Java 9에서 더 이상 사용되지 않으며 Java 14에서 제거되었습니다.
- 데이터 세트가 거대한 크기에 도달하거나 막대한 힙을 수집할 때 상대적으로 비효율적입니다.
- 동시 단계에서 애플리케이션이 GC와 리소스를 공유해야 합니다.
- GC 작업에 전반적으로 더 많은 시간이 소요되므로 처리량 문제가 있을 수 있습니다.
- 전반적으로 대부분 동시성으로 인해 더 많은 CPU 시간을 사용합니다.
4.4. G1(쓰레기 우선) GC
G1은 여러 백그라운드 GC 스레드를 사용하여 CMS처럼 힙을 스캔하고 지웁니다. 실제로 핵심 Java 팀은 G1을 CMS보다 개선된 것으로 설계하여 추가 전략으로 일부 약점을 패치했습니다.
증분 및 동시 수집 외에도 이전 애플리케이션 동작 및 GC 일시 중지를 추적하여 예측 가능성을 달성 합니다. 그런 다음 대부분 쓰레기로 가득 찬 가장 효율적인 영역에서 먼저 공간을 회수하는 데 중점을 둡니다. 이런 이유로 Garbage-First 라고 부릅니다 .
Java 9부터 G1은 서버급 컴퓨터의 기본 수집기입니다. 명령줄에 -XX:+UseG1GC 를 제공하여 명시적으로 활성화할 수 있습니다 .
장점:
- 거대한 데이터 세트에서 매우 효율적입니다.
- 다중 프로세서 시스템을 최대한 활용합니다.
- 일시 중지 시간 목표를 달성하는 데 가장 효율적입니다.
단점:
- 엄격한 처리량 목표가 있을 때는 최선이 아닙니다.
- 동시 수집 중에 애플리케이션이 GC와 리소스를 공유해야 합니다.
G1은 거래 플랫폼이나 대화형 그래픽 프로그램과 같은 실시간 응용 프로그램과 같이 매우 엄격한 일시 중지 시간 목표와 적당한 전체 처리량이 있는 응용 프로그램에 가장 적합합니다.
4.5. Z 가비지 수집기(ZGC)
ZGC는 확장 가능한 저지연 가비지 수집기입니다. 멀티 테라바이트 힙에서도 낮은 일시 중지 시간을 유지합니다. 참조 색상 지정, 재배치, 로드 장벽 및 재매핑을 포함한 기술을 사용합니다. 큰 힙이 일반적이고 빠른 애플리케이션 응답 시간이 필요한 서버 애플리케이션에 적합합니다.
실험적 GC 구현으로 Java 11에 도입되었습니다. 명령줄에서 -XX:+UnlockExperimentalVMOptions -XX:+UseZGC 를 제공하여 명시적으로 활성화할 수 있습니다 . 자세한 설명 은 Z Garbage Collector에 대한 기사를 참조하십시오.
5. 결론
많은 애플리케이션의 경우 수집기 선택은 일반적으로 JVM 기본값으로 충분 하므로 문제가 되지 않습니다 . 이는 응용 프로그램이 허용 가능한 빈도 및 기간의 일시 중지와 함께 가비지 수집이 있을 때 잘 수행될 수 있음을 의미합니다. 그러나 이것은 대규모 애플리케이션, 특히 방대한 데이터 세트, 많은 스레드 및 높은 트랜잭션 속도를 가진 애플리케이션의 경우에는 해당되지 않습니다.
이 기사에서는 JVM에서 지원하는 가비지 수집기를 살펴보았습니다. 또한 애플리케이션의 요구 사항에 맞는 수집기를 선택하는 데 도움이 되는 주요 변수도 살펴보았습니다.