티스토리 뷰

IT/Java

Java의 메모리 구조와 GC 완전 정복

Stv 2025. 4. 14. 20:03

목차


    1. Java 프로그램 실행 과정 다시 짚고 가기

    1.  .java -> 컴파일 -> .class (바이트코드 생성)
    2.  JVM이 Class Loader로 로딩
    3.  메모리 영역(Runtime Data Area)에 적재
    4.  실행 엔진(Execution Engine)이 해석 & 실행
    5. 실행 중 발생하는 객체/변수 등이 JVM 메모리 영역에 저장됨
    • 즉, 우리가 작성한 모든 Java 코드는 결국 JVM 메모리 공간을 점유하게 되며, 메모리 구조의 이해 = 성능과 안전성 이해의 첫걸음

    2. JVM의 메모리 영역 정리 (Java 8 기준)

     

    📌 JVM Runtime Data Area 구성

     

    영역 설명 생성 시점 스레드 공유 여부
    Heap 객체 인스턴스 저장, GC의 대상 클래스 로딩 시  ✅ 공유
    Method Area (-> MetaSpace) 클래스 정보, static 변수, constant pool 클래스 로딩 시  ✅ 공유
    Stack 지역 변수, 참조 주소, 메서드 호출 정보 스레드 생성 시 ❌ 개별
    PC Register 현재 실행 중인 명령어 주소 스레드 생성 시 ❌ 개별
    Native Method Stack JNI를 통한 C/C++ 실행 시 사용 스레드 생성 시 ❌ 개별

     

    3. Heap 영역의 상세 구조

    GC는 Heap을 중심으로 작동한다.

     

    🔷 Heap 내부 구조 (Java 8 기준)

    Heap
     └─ Young Generation
         ├─ Eden
         └─ Survivor 0 / Survivor 1
     └─ Old Generation

     

    📌 Young Generation

    • 객체가 처음 생성되는 공간
    • GC가 자주 발생(Minor GC)
    • 대부분 객체는 이곳에서 생성되고 바로 소멸됨

    📌 Eden

    • 객체가 제일 먼저 생성되는 공간
    • 생존 시 Servivor 영역으로 이동

    📌 Survivor 0 / 1

    • Eden에서 살아남은 객체들이 일시적으로 이동하는 공간
    • Survivor 영역을 왔다 갔다 하며 생존 횟수(teruring threshold)를 넘기면 Old로 이동

    📌 Old Generation

    • 오래 살아남은 객체가 저장되는 공간
    • Full GC(또는 Major GC)의 대상이 됨 

    4. Method Area (-> metaSpace)

    📌 Java 8부터 PermGen -> MetaSpace로 변경

    PermGen MetaSpace
    JVM 메모리 내부 Native 메모리 사용 (OS에 의존)
    사이즈 고정 -> OOM발생 가능 제한 없음 (옵션으로 설정 가능)

     

    클래스 정보(Class metadata), static 필드, constant pool 등이 저장됨
    실무에서 클래스 수가 많아지면 OOM in MetaSpace 발생 가능

     

    5. Stack 영역

    • 스레드마다 독립적인 공간
    • 각 메서드 호출 시 스택 프레임 생성
    • 지역 변수, 매개 변수, 리턴 주소 등 저장
    StackOverflowError는 재귀 호출이 너무 깊어질 때 발생

     

    6. GC(Garbage Collection)의 역할과 전략

     

    📌 GC의 목적

    • 개발자가 명시적으로 free() 하지 않아도 메모리를 자동으로 회수
    • 성능에 큰 영향 -> GC가 자주/오래 발생하면 애플리케이션 지연 발생

    🔁 GC 동작 원리 (기본 흐름)

    1. Mark -> 사용 중인 객체 식별
    2. Sweep -> 사용하지 않는 객체 제거
    3. Compact -> 메모리 조각 정리 (Old 영역 중심)

    🌀 GC의 종류

    구분 설명
    Minor GC Young 영역에서 발생, 빠르고 자주 일어남
    Major GC (Full GC) Old 영역 포함 전체 GC, 느리고 애플리케이션 일시 정지 (Stop-the-world 발생)

     

    7. 주요 GC 알고리즘

    GC 종류 특징 설명
    Serial GC 단일 스레드  소형 어플리케이션용
    Parallel GC 멀티스레드 Throughput 중심, 기본 GC 방식
    CMS (Concurrent Mark Sweep) 응답 시간 최소화 Mark-Sweep을 병렬로 수행, stop-the-world 시간 감소
    G1 GC Java 9+ 기본 Young/Old 영역을 Region 단위로 분할, 병렬 GC + 예측 가능성 높음
    CMS는 현재 G1 GC로 대체 권장됨

     

    8. 실무에서 발생하는 메모리 문제 유형

     

    문제 원인 해결 방향
    OOM (OutofMemoryError) 힙 or 메타스페이스 부족 힙 사이즈 조정, 객체 참조 해제
    Full GC 반복 Old 영역 꽉 참 GC 튜닝, 객체 생명주기 단축
    클래스 로딩 메모리 초과 PermGen/MetaSpace 부족 -XX:MaxMetaspaceSize 조정
    StackOverflowError 무한 재귀 재귀 탈출 조건 확인

     

    9. GC 튜닝 시 주요 JVM 옵션

     

    # Heap 영역 크기
    -Xms512m      # 초기 힙 사이즈
    -Xmx1024m     # 최대 힙 사이즈
    
    # GC 로그 출력
    -verbose:gc
    -Xloggc:gc.log
    -XX:+PrintGCDetails
    -XX:+PrintGCDateStamps
    
    # GC 종류 지정
    -XX:+UseG1GC
    -XX:+UseParallelGC
    -XX:+UseConcMarkSweepGC

     

    ✅ 마무리 요약

    • Java의 메모리는 Heap, Stack, Method Area 등으로 나뉘며 각자 역할이 다르다.
    • GC는 주로 Heap 대상으로 하며, Young -> Old 객체로 옮겨가며 관리한다.
    • GC 종류는 애플리케이션 특성에 따라 선택해야 하며, G! GC가 현재 가장 일반적이다.
    • 메모리 관련 문제는 흔히 발생하며, JVM 튜닝과 GC 로그 분석 능력이 실무에서 중요하다.

    🔜 다음 포스팅 주제로는 객체 지향의 4대 특성과 SOLID 원칙에 대해 보다 깊게 파고들어가 보려고 한다.