[Java 기본 원리] GC(가비지 컬렉션)의 모든 것

JVM의 GC(Garbage Collection)는 자동으로 메모리를 관리하며, 다양한 알고리즘을 통해 최적화된 메모리 관리를 제공한다. GC동작으로 메모리 낭비하는 코드도 살펴보자. 그리고 GC 튜닝의 목적과 G1 GC 부터는 튜닝을 크게 하지 않는 이유를 알아보자.


JVM은 자동으로 Garbage Collection 를 수행하며, 사용하지 않는 객체들을 메모리에서 제거한다.

  • 예로 String 객체를 재할당 하면 힙에 새로운 공간을 할당하므로 사용하지 않는 메모리가 생성된다.
    → 이를 GC가 자동 제거



메모리 낭비와 문제점 ⚡

메모리 누수 사례:
배열을 new로 새로 할당 함으로써 기존 배열[3] 크기가 가비지(쓰레기) 된다

// 이런 코드는 가급적 지양하자
int[][] intArray = new int[4][3]; // 아래 코드로 인해 GC
intArray[0] = new int[4]; // 기존 [3] 크기 가비지
intArray[1] = new int[2]; // 기존 [3] 크기 가비지
intArray[2] = new int[10]; // 기존 [3] 크기 가비지
intArray[3] = new int[400]; // 기존 [3] 크기 가비지


문제점

  • 메모리 누수: GC로 회수되지 않는 메모리 누적 - Out of memory
    • 메모리 누수를 막기 위해선 변수가 최소한의 범위에서 존재하도록 해야한다.
  • 스택 오버플로우: 스택 메모리 공간 부족



GC 종류와 특징 💡

기본 GC 유형(Full GC 기준)

  • Serial GC : 단일 스레드에서 GC 처리
  • Parallel GC : GC를 병렬로 처리하여 멀티코어 시스템 성능 향상
  • CMS (Concurrent Mark-Sweep) GC : 장시간 멈춤 없는 GC 제공 (대규모 서버에 적합)
  • G1 (Garbage-First) GC : 짧은 일시 중지 시간을 제공 → 최신 방안



메모리 영역 구조

용어정리

  • Young Generation(New Generation): 새로 생성된 객체들이 할당되는 영역

    1. Eden: 새로운 객체 할당

    2. Survivor(S0, S1): 살아남은 객체 보관

  • Old Generation: Young Generation에서 살아남은 객체들이 이동하는 영역
    • 오래 살아남은 객체 저장
  • Permanent Generation (PermGen): 클래스 메타데이터를 저장하는 영역
    • 자바8 이후로 메타스페이스(Metaspace)로 대체!
  • Minor GC: Young Generation에서 발생하는 가비지 컬렉션(GC)
  • Major GC(=Full GC): Old Generation에서 발생하는 가비지 컬렉션(GC)
    • Full GC 알고리즘 종류 : Serial GC, Parallel GC, G1 GC 등


JVM 메모리 구조 보충 설명 -> 참고: JVM의 동작 원리와 메모리 구조 총정리

  1. Heap: Java 객체들이 저장되는 공간
    • 생명주기 짧은? New Generation
    • 생명주기 긴? Old Generation
  2. Stack: 메소드 호출시 해당 메소드의 매개변수, 지역변수, 임시변수 등을 저장하는 공간
  3. Native Heap(native method stack): Native 객체들이 거주하는 공간
    • OS단 에서 결정되며 Java 객체들은 저장되지 않음
  4. Permanent Generation(static=method=metaspace area): Class 객체에 대한 정보를 저장하는 공간

JVM 메모리 구조


Hotsopt Heap



GC 동작 방식 🔍

  1. 객체 생성
    • 객체가 생성되면, New Generation의 Eden 영역에 할당!
  2. Minor GC
    1. Eden 영역 가득 차면 Minor GC는 Eden 영역을 스캔하여 살아있는 객체를 두개의 Survivor중 하나로 이동
    2. 이후, Eden 영역이 비워 짐
    3. 하나의 Survivor 영역에서 살아남은 객체는 다른 Survivor 영역으로 이동
      => 이 과정은 여러 번 반복된다.
      • Survivor0에 살아있는 객체 있으면 Survivor1로 복사 후 Survivor0는 Clear
        → 반대라면 반대로 동작
      • 따라서 Survivor 두 영역중 하나는 반드시 비어있다.
        만약 두 영역 모두 데이터 존재하거나, 사용량이 0이면 비정상
    4. 오래 살아남은 객체는 Old Generation로 이동
  3. Major GC (Full GC)

    Major GC와 Full GC는 Minor GC보다 시간이 많이 걸리며, 애플리케이션의 응답 시간이 길어질 수 있다.

    1. Old Generation 가득 차면 Major GC 또는 Full GC가 발생!
      • Major GC는 Old Generation의 객체들을 대상으로 검사
      • Full GC는 Old Generation뿐만 아니라 New Generation과 메타스페이스의 모든 객체를 검사



GC 튜닝이란? 💡

GC를 실행하기 위해 JVM이 어플리케이션의 실행을 멈춘다. 이를 Stop-the-world라고 한다.

GC 튜닝의 목적? → Stop-the-world의 시간을 줄이는 것



G1 GC의 혁신 ⚡

G1 GC 부터는 GC 튜닝을 크게 하지 않는다. 최적화가 너무 잘 되어 있어서!

  • 자동 최적화로 튜닝 최소화 => 기존 “생존 기간” 기준, 현재 “Region” 기준
    • Region(작은 동일한 크기) 기반 메모리 관리로써 가비지가 가장 많은 영역부터 GC 진행!
      전체 힙을 스캔하는 이전보다 튜닝을 덜 하게 됨
  • 병렬 처리 지원


참고 : https://inpa.tistory.com/entry/JAVA-☕-가비지-컬렉션GC-동작-원리-알고리즘-💯-총정리

댓글남기기