본문 바로가기

Programming/Java

JVM의 구조와 GC(Garbage Collection) 방식 이해하기

반응형

 

1. JVM이란?

JVM(Java Virtual Machine)은 자바 애플리케이션을 실행하기 위한 가상 머신이다. 자바로 작성된 코드는 .java → .class 파일로 컴파일되고, 이 바이트코드를 JVM이 해석하거나 컴파일하여 실행한다.
JVM은 운영체제 위에서 동작하며, 자바 프로그램이 플랫폼에 독립적으로 실행될 수 있도록 해주는 핵심 요소다.


2. JVM의 주요 구성 요소

JVM은 크게 실행 엔진과 메모리 영역으로 나뉘며, 각 구성 요소는 다음과 같은 역할을 수행한다.

2.1 Class Loader Subsystem

  • 클래스 파일을 메모리로 로드하고, 검증 및 초기화 과정을 수행한다.

2.2 Runtime Data Area (메모리 영역)

  • JVM이 애플리케이션을 실행하는 동안 사용하는 메모리 공간이다.
영역 설명
Heap new로 생성된 객체와 배열이 저장되는 공간. GC의 주요 대상
Stack 각 스레드마다 생성되며, 메서드 호출 시의 지역 변수와 프레임 정보 저장
Method Area 클래스 정보, static 변수, 상수 풀 등이 저장
PC Register 현재 실행 중인 명령어 주소 저장
Native Method Stack 네이티브 코드 실행 시 사용되는 스택

2.3 Execution Engine

  • 바이트코드를 기계어로 변환하여 실행
  • JIT(Just-In-Time) 컴파일러가 성능 최적화를 위해 사용됨

3. JVM Heap 구조

Heap 영역은 Young Generation과 Old Generation으로 나뉜다.

  • Young Generation: 새로 생성된 객체가 저장된다. 이 영역에서 발생하는 GC는 Minor GC라고 한다.
  • Old Generation: Young 영역에서 일정 시간 이상 살아남은 객체들이 이동하는 공간이다. 이 영역에 대한 GC는 Major GC라고 한다.
  • Metaspace: 클래스 메타데이터가 저장되는 공간. JDK 8 이후 PermGen을 대체함.

4. Garbage Collection(GC) 방식

GC는 사용되지 않는 객체를 메모리에서 제거해주는 자동 메모리 관리 기능이다. GC 방식은 다음과 같이 구분된다.

4.1 Serial GC

  • 단일 스레드로 GC를 수행
  • 구조가 단순하고 작은 애플리케이션에 적합
  • -XX:+UseSerialGC

4.2 Parallel GC

  • 여러 스레드를 사용해 GC를 병렬로 수행
  • Throughput(전체 처리량)을 중시하는 시스템에 적합
  • -XX:+UseParallelGC

4.3 CMS GC (Concurrent Mark Sweep)

  • Stop-the-world 시간을 최소화하기 위해 GC 작업을 병렬로 나누어 수행
  • 단점으로는 메모리 단편화 문제가 존재
  • -XX:+UseConcMarkSweepGC (JDK 9 이후 deprecated)

4.4 G1 GC (Garbage First)

  • 힙을 작은 Region 단위로 나누고, GC Pause를 예측 가능하게 조절
  • 최근 JVM의 기본 GC 방식으로 사용되는 경우가 많음
  • -XX:+UseG1GC

4.5 ZGC / Shenandoah

  • 지연 시간을 매우 짧게 유지할 수 있도록 설계된 최신 GC 방식
  • 수백 GB 이상의 대용량 힙을 효율적으로 처리
  • -XX:+UseZGC, -XX:+UseShenandoahGC

5. GC가 중요한 이유

GC의 동작 방식은 애플리케이션의 성능, 응답 속도, 안정성에 직접적인 영향을 준다. GC가 자주 발생하거나 정리 시간이 길어지면 다음과 같은 문제가 발생할 수 있다.

  • 애플리케이션 응답 지연 (GC pause)
  • OutOfMemoryError 발생
  • 시스템의 CPU 사용률 상승 및 처리량 감소

따라서, 시스템의 특성과 목적에 맞는 GC 방식을 선택하고 적절히 튜닝하는 것이 매우 중요하다.


6. GC 방식 선택 가이드

환경 적합한 GC
단순 구조, 리소스 적음 Serial GC
높은 처리량 필요 Parallel GC
멈춤 시간 최소화 CMS, G1 GC
대규모 서비스, TB 단위 Heap ZGC, Shenandoah

7. JVM은 기본적으로 GC를 선택한다

  • JVM은 Java 버전에 따라 기본으로 사용하는 GC 방식이 다르다.
    • 예를 들어, Java 8에서는 Parallel GC가 기본이고,
    • Java 9 이상에서는 G1 GC가 기본이다.
  • 특별히 명시하지 않으면 JVM이 알아서 적절하다고 판단하는 GC를 사용하게 된다.

8. 원하는 GC를 명시적으로 설정할 수 있다

JVM 실행 옵션을 통해 GC 방식을 직접 설정할 수 있다. 예를 들어:

java -XX:+UseG1GC -jar myapp.jar

 

GC 종류 설정 옵션
Serial GC -XX:+UseSerialGC
Parallel GC -XX:+UseParallelGC
CMS GC (JDK 8까지) -XX:+UseConcMarkSweepGC
G1 GC -XX:+UseG1GC
ZGC (JDK 11+) -XX:+UseZGC
Shenandoah (JDK 12+/RedHat 기반) -XX:+UseShenandoahGC

주의: JVM 버전마다 지원하는 GC가 다르므로, 선택하기 전에 현재 사용하는 Java 버전이 해당 GC를 지원하는지 확인해야 한다.


9. GC 선택은 단순히 "바꾸면 끝"은 아니다

GC를 변경하면 다음과 같은 영향이 있다:

  • Pause 시간이 달라짐
  • CPU 사용량이 달라짐
  • 메모리 사용 패턴이 달라짐
  • 기존 설정들 (-Xmx, -Xms, -XX:SurvivorRatio 등)도 GC에 따라 다르게 작용할 수 있음

따라서, 단순히 -XX:+UseZGC와 같은 옵션만 추가하는 것보다는,
어떤 GC가 어떤 특징을 가지고 있는지 이해하고,
시스템의 요구 사항 (지연시간 vs 처리량 등) 에 맞춰 선택하는 것이 중요하다.


10. 어떤 GC를 선택해야 할지 모를 때는?

  • 지연 시간에 민감한 애플리케이션 (예: 게임, 실시간 거래 시스템) → G1 GC, ZGC, Shenandoah
  • 배치 처리, 서버 리소스를 최대 활용하는 시스템 → Parallel GC
  • 리소스 제한이 있는 임베디드 환경 → Serial GC
  • 아직은 크게 상관 없고, 기본값이면 충분한 경우 → JVM 기본 설정 유지 (대부분 G1 GC)

11. 내 애플리케이션이 현재 어떤 GC를 쓰는지는 어떻게 알 수 있나?

GC 로그를 확인하거나, 실행 시 다음과 같은 옵션으로 JVM 설정을 출력해볼 수 있습니다:

java -XX:+PrintCommandLineFlags -version

 

출력 결과에 UseG1GC, UseParallelGC 등 어떤 GC가 활성화되어 있는지 확인할 수 있다.

반응형