CS/JVM (12) 썸네일형 리스트형 [JVM] 내 Java 애플리케이션, 혹시 Serial GC로 동작하고 있진 않을까? Spring Boot 애플리케이션을 Docker 컨테이너에 올려 운영하고 있다면, 한 가지 확인해볼 것이 있다. 바로 GC(Garbage Collector)가 의도한 대로 선택되어 동작하고 있는지다.JVM은 실행 환경의 CPU 코어 수와 물리 메모리를 기반으로 GC를 자동 선택하는 Ergonomics라는 메커니즘을 갖고 있다. 문제는 Docker 컨테이너 환경에서 리소스 제한을 어떻게 거느냐에 따라, 개발자가 의도하지 않은 GC가 선택될 수 있다는 점이다. 1. 서버 클래스와 GC 자동 선택JVM은 실행 환경을 서버 클래스(Server-Class)와 클라이언트 클래스(Client-Class)로 구분하고, 이에 따라 기본 GC를 자동 선택한다. 구분 조건JDK 9+ 기본 GC서버 클래스CPU 2코어 이상 .. [JVM 밑바닥까지 파헤치기] JVM 가비지 컬렉터의 역사 (6) - ZGC와 Generational ZGC: 서브밀리초 GC의 모든 것 이전 포스트에서 Shenandoah가 Brooks Pointer를 사용해 동시 압축을 구현했다면, ZGC는 완전히 다른 접근 방식을 택한다. Colored Pointer와 Load Barrier라는 기법으로 같은 목표를 달성하면서도, 구현 전략은 정반대에 가깝다. 1. ZGC 개요ZGC란?ZGC(Z Garbage Collector)는 JDK 11에서 실험적 기능으로 처음 도입되고, JDK 15에서 프로덕션 레디 상태가 된 저지연(Low-Latency) 가비지 컬렉터다. Oracle이 개발했으며, 'Z'라는 이름에는 특별한 의미가 없다(ZFS 파일시스템에 대한 오마주라고 알려져 있다). ZGC의 핵심 설계 목표는 다음과 같다.초저지연: GC 일시 정지 시간을 서브밀리초(sub-millisecond) 수준으.. [JVM 밑바닥까지 파헤치기] JVM 가비지 컬렉터의 역사 (5) - Shenandoah GC: 동시 이주 실현한 Low-Latency 가비지 컬렉터 서론: 왜 Low-Latency GC가 필요해졌는가하드웨어 성장이 만든 역설1990년대부터 2000년대 초반까지 JVM 힙 메모리는 수백 MB 수준이었습니다. 그러나 메모리 가격 하락과 64비트 아키텍처의 보편화로 상황이 완전히 달라졌습니다. 이제는 수십에서 수백 GB 힙을 사용하는 애플리케이션이 흔합니다. 문제는 Parallel GC 같은 전통적인 처리량 중심 컬렉터에서 발생했습니다. 이들 컬렉터는 힙 크기에 비례해서 Stop-The-World(STW) 시간이 늘어납니다. 4GB 힙에서 100ms였던 Full GC가 64GB 힙에서는 수 초가 걸릴 수 있습니다. 하드웨어가 좋아졌는데 오히려 멈춤 시간은 더 길어지는 역설적인 상황이 된 것입니다. 애플리케이션 특성의 변화현대 애플리케이션은 지연 시간에 훨.. [JVM 밑바닥까지 파헤치기] JVM 가비지 컬렉터의 역사 (4) - G1: 새로운 패러다임 들어가며이전 편에서 CMS의 한계를 살펴봤습니다. Fragmentation, Concurrent Mode Failure, 예측 불가능한 pause time... 이 문제들을 해결하기 위해 완전히 새로운 접근이 필요했습니다. 이번 편에서는 G1(Garbage-First) GC를 다룹니다. Java 9부터 기본 GC가 된 G1은 기존 컬렉터들과 근본적으로 다른 구조를 가집니다. G1의 설계 목표G1은 다음을 목표로 설계되었습니다:예측 가능한 pause time: 목표 시간 내에 GC 완료Compaction 포함: Fragmentation 문제 해결대용량 힙 지원: 수십 GB 힙에서도 효율적CMS 대체: CMS의 장점은 유지, 단점은 해결-XX:+UseG1GC (Java 9부터 기본)-XX:M.. [JVM 밑바닥까지 파헤치기] JVM 가비지 컬렉터의 역사 (3) - 동시성 컬렉터: CMS 들어가며이전 편에서 병렬 컬렉터의 한계를 살펴봤습니다. throughput은 좋아졌지만, STW 자체는 없앨 수 없었습니다. 특히 대용량 힙에서 Major GC가 발생하면 수 초간 멈추는 문제가 있었죠.이번 편에서는 애플리케이션과 동시에 GC를 수행하는 CMS(Concurrent Mark Sweep)를 다룹니다. CMS의 목표CMS의 핵심 목표는 짧은 pause time입니다.Parallel GC: "멈추는 건 어쩔 수 없어. 대신 빨리 끝내자."CMS: "멈추는 시간 자체를 최소화하자. 대부분의 작업은 앱이 돌아가면서 하자."-XX:+UseConcMarkSweepGC CMS의 구조CMS는 Old 영역 전용 컬렉터입니다. Young 영역은 ParNew가 담당합니다.┌───────────────────.. [JVM 밑바닥까지 파헤치기] JVM 가비지 컬렉터의 역사 (2) - 병렬 컬렉터: ParNew, Parallel Scavenge, Parallel Old 들어가며이전 편에서 Serial GC의 한계를 살펴봤습니다. 멀티코어 시대가 도래하면서, 여러 스레드를 활용해 GC를 병렬로 수행하는 컬렉터들이 등장합니다.이번 편에서는 ParNew, Parallel Scavenge(PS), Parallel Old를 다룹니다. 병렬 GC의 목표Serial GC의 가장 큰 문제는 싱글 스레드였습니다:[Serial GC - 4코어 CPU에서]Core 1: ████████████ (GC 수행)Core 2: ____________ (놀고 있음)Core 3: ____________ (놀고 있음)Core 4: ____________ (놀고 있음)→ CPU의 75%가 낭비됨병렬 GC는 이를 해결합니다:[Parallel GC - 4코어 CPU에서]Core 1: ███ (GC)Core .. [JVM 밑바닥까지 파헤치기] JVM 가비지 컬렉터의 역사 (1) - 초기 컬렉터: Serial & Serial Old 들어가며JVM의 가비지 컬렉터는 20년 넘게 발전해왔습니다. 이 시리즈에서는 클래식 가비지 컬렉터들의 발전 흐름을 따라가며, 각 컬렉터가 왜 등장했고, 어떤 문제를 해결하려 했는지 살펴보겠습니다.첫 번째 편에서는 가장 기본이 되는 Serial GC와 Serial Old GC를 다룹니다. GC의 기본 개념 복습본격적인 설명에 앞서, GC의 핵심 개념을 짚고 넘어가겠습니다. 세대별 가설 (Generational Hypothesis)대부분의 JVM GC는 Weak Generational Hypothesis를 기반으로 합니다:"대부분의 객체는 젊어서 죽는다"이 가설에 따라 힙을 Young 영역과 Old 영역으로 나누고, Young 영역을 더 자주 수집합니다.┌─────────────────────────────.. [JVM 밑바닥까지 파헤치기] HotSpot GC의 상세 구현 기법 이번 글에서는 HotSpot VM이 GC를 효율적으로 수행하기 위해 사용하는 구현 기법들을 정리합니다. 루트 노드 열거의 최적화부터 동시성 GC의 객체 소실 방지까지 다룹니다. 루트 노드 열거와 OopMapStop the World루트 노드 열거 작업은 반드시 일관된 스냅숏 상태에서 진행되어야 합니다. 열거 도중에 참조 관계가 바뀌면 정확한 분석이 불가능하기 때문입니다.그래서 루트 노드 열거 시점에는 모든 애플리케이션 스레드가 멈춥니다. 이를 Stop the World(STW)라고 합니다. 어떤 GC를 사용하든 루트 노드 열거 단계에서는 STW가 발생합니다. 문제: GC Roots를 어떻게 빠르게 찾을까?도달 가능성 분석을 하려면 먼저 GC Roots를 찾아야 합니다. GC Roots 중 하나가 스택 프.. 이전 1 2 다음