JVM - Runtime Data Area - Heap

JVM 의 Runtime Data Area 중 Heap 영역에 대해서 알아봅니다.

Heap 영역

  • JVM 에서 new 연산자를 통해 생성되는 모든 객체와 배열이 저장되는 공유 메모리 영역
  • 모든 스레드가 이 영역에 접근 할 수 있으므로, 동시성이 중요한 부분이기도 함
  • 목적
    • 객체 / 배열 / 객체 헤더 정보 등이 저장됨
    • 프로그램 실행 중에 필요 한 만큼 객체를 생성하고, 그 수명이 끝난 객체들을 회수하여 메모리 사용을 최적화
  • JVM 옵션
    • -Xms / -Xmx 옵션을 통해, 힙의 초기 크기와 최대 크기를 지정 할 수 있음
    • 어플리케이션의 메모리 사용 패턴에 맞춰 조정하며, GC 성능 및 어플리케이션의 전체 성능에 큰 영향을 미침
  • 동시성
    • 힙은 여러 스레드가 공유하는 영역이기 때문에, 동시성 문제가 발생 할 수 있음
    • 이를 해결하기 위해, JVM은 다양한 동기화 기법 및 GC 알고리즘을 활용 하여, 동시 접근과 메모리 일관성 문제를 해결
  • 메모리 최적화
    • 객체의 재사용, 객체 풀링, interned 문자열 같은 최적화 기법을 통해 힙의 효율성을 극대화
    • GC 로그 분석이나, Heap Dump 등을 통해 어플리케이션의 메모리 사용 상태를 모니터링 하고 튜닝 할 수 있음
  • 성능 / 안정성
    • 힙 영역의 크기와 GC 알고리즘의 선택은, JVM 성능과 어플리케이션 응답 속도에 직접적인 영향을 미침
    • 올바른 힙 튜닝은 OOM 같은 문제를 예방하고 시스템 안정성성을 높일 수 있음

Heap memory 구조

  • Young Generation
    • 방금 생성된 객체가 먼저 놓이는 곳
    • Eden 영역
      • 객체가 생성된 직후엔, 기본적으로 이 영역에 할당 됨
      • Eden 에서 대부분의 객체는 사용 후 GC에 의해 제거 됨
    • Survivor 영역
      • Eden 영역에서 사용 되고 남은 객체들은 두 개의 작은 공간 ( S0, S1 ), 즉 Survivor 영역으로 이동 됨
      • 객체는 한 Survivor 영역에서 다른 Survivor 영역으로 복사 되면서, 반복적으로 살아남을 경우 나중에 Old Generation 으로 이동 됨
  • Old Generation ( Tenured Generation )
    • 젊은 세대를 여러 번 거쳐 살아남은 객체들이 저장 됨
    • Young generation 보다 GC 주기가 길고, 한번에 많은 객체를 처리하지 않음
    • GC시, 객체 이동 및 복사 비용이 더 많이 드는 경우가 있기 때문에, GC 알고리즘에 따라 압축 / 복잡한 알고리즘이 활용 됨

Garbage collection

  • Young generation GC ( Minor GC )
    • Copying Collection 방식으로 동작
      • Eden 영역에 할당된 대부분의 객체는, 생성 후 사용되지 않으면 Minor GC 에 의해 제거
      • 살아남은 객체는 Eden 에서, Survivor 영역 중 하나로 복사
      • Survivor 영역 간에는 교대로 복사 하면서, 살아남은 객체들을 옮김
      • 여러 GC 사이클을 통과한 객체는 Old Generation 으로 승격
    • 특징
      • 대부분의 객체가 빠르게 사라지기 때문에, 복사 알고리즘이 빠르고 단순하며, 파편화도 줄일 수 있음
  • Old generation GC ( Major GC / Full GC )
    • Mark-Sweep
      • Mark → 힙 내 모든 객체를 탐색하여, 도달 가능한 객체와 도달 불가능한 객체를 표시
      • Sweep → 도달 불가능한 객체들을 메모리에서 해체
      • Mark & Sweep 단계는, 도달 불가능한 객체들을 메모리에서 해제 한 뒤, 재정리 작업이 없음
      • 따라서, 메모리 조각화 ( 단편화 ) 문제가 생길 수 있음
    • Mark-Compact
      • Mark 후에, 살아있는 객체들을 한쪽으로 밀어 모으고, 남은 빈 공간을 하나로 합침
      • 조각화 문제가 줄어들지만, 객체를 이동하는 복사 비용이 추가 됨
    • G1 GC ( Garbage First GC )
      • 영역 기반 ( Region-based ) GC로, 힙을 작은 영역 ( Region ) 으로 나누어 처리
      • 각 영역의 GC 우선 순위를 정해, 가장 많은 쓰레기가 있는 영역부터 청소하는 방식으로 동작
      • G1 GC는 단편화 문제를 해결하고, 예측 가능한 짧은 GC 정지를 목표로 함
      • 정지 시간 목표 ( Pause-Time Goal )을 지정 할 수 있어, 예측 가능한 정지 시간을 제공
      • 많은 JVM의 기본 GC로 채택되어 있음
      • Young / Old Generation 경계를 넘어 전체 힙을 효율적으로 관리 할 수 있음
      • 대규모 힙 환경에서 특히 유리하며, Full GC가 아닌 병렬적 / 지역적 GC를 통해 응답 지연이 줄어 듬
    • Full GC 진행 될 땐, 자바 어플리케이션이 멈출 수 있는 이슈가 있음 ( stopping-the-world )
  • 다른 GC 알고리즘들
    • Serail GC
      • 단일 스레드로 GC 작업을 수행하는 단순한 GC 알고리즘
      • 작은 어플리케이션, 단일 CPU 환경에서 주로 활용
      • 작은 힙 환경 / 개발 및 테스트 단계에서 많이 활용 되고, 멀티 코어 환경에서 병렬 처리 능력이 부족해 전체 어플리케이션 처리량이 낮음
    • Parallel GC ( Throughput GC )
      • 여러 스레드를 활용하여 GC 작업을 병렬로 수행
      • Young Generation의 Minor GC 작업에 많이 사용되며, Full GC도 병렬로 수행 가능한 경우가 많음
      • 서버 어플리케이션 등, 많은 CPU 코어를 가진 시스템에서 높은 처리량을 목표로 하는 환경에서 적합
      • 병렬로 GC가 수행되어, 전체 GC 시간이 단축되고, 처리량이 향상 됨
      • 멀티 스레드 GC의 경우 정지 시간이 길어 질 수 있으나, 높은 처리량을 우선시 하는 환경에서 채택
    • Concurrent Mark-Sweep
      • 대부분의 GC 작업을 어플리케이션 스레드와 동시에 진행하여, 정지 시간을 줄이는데 초점을 맞춤
      • Pause time 을 최소화 해야 하는 대화형 어플리케이션이나, 실시간 시스템에 적합
      • 메모리 단편화가 발생 할 수 있으며, 추가적인 동시 실행 오버헤드가 있을 수 있음