[Alex] 데이터 장인의 블로그

[JVM] JVM의 Garbage Collector (Feat. 튜닝을 위해서..) 본문

Hadoop & Spark

[JVM] JVM의 Garbage Collector (Feat. 튜닝을 위해서..)

Alex, Yoon 2023. 1. 24. 21:35

저번 글에 이어서 GC에 대해 공부해보고자 한다. 

2022.12.19 - [Hadoop & Spark] - [JVM] 기본 개념 정리

Garbage Collector 

Heap 영역에서 동적으로 할당된 객체 중 사용하지 않은 객체을 탐지하여 해제하는 기능. 

한정된 Heap 메모리를 효율적으로 사용하기 위한 방법. 자바 이전에는 프로그래머가 모든 프로그램 메모리를 관리했다고 한다. 하지만 자바에서는 JVM이 가비지 컬렉션이라는 프로세스를 통해 프로그램 메모리를 관리한다. 가비지 컬렉션은 자바 프로그램에서 사용되지 않는 메모리를 지속적으로 찾아내서 제거하는 역할을 한다.

단점 : GC 작업은 순수 오버헤드로 프로그램이 해야할 일을 하지 못하도록 하는 순간이다. 

Mark and Sweep

[10분 테코톡] 🤔 조엘의 GC

Java가 채택하고 있는 Mark & Sweep 방식은 루트에서부터 해당 객체에 접근이 불가능한 (Unreachable)지를 확인한 후에, 모두 삭제한다. 

단점 : 의도적으로 GC를 실행시켜야 한다. 어플리케이션 실행과 GC의 실행이 병행된다. 

Stop-the-world

GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것. 이 시간을 최소화 하는 것이 GC를 최적화하는 방법. 

어떤 GC 알고리즘을 사용하더라도 stop-the-world 는 발생하게 되는데, 대개의 경우 GC 튜닝은 이 stop-the-world 시간을 줄이는 것이다. GC를 해도 더 이상 사용 가능한 메모리 영역이 없는데 계속 메모리를 할당하려고 하면, OutOfMemoryError가 발생하여 WAS가 다운될 수도 있다. 

 

행(Hang) 

서버가 요청을 처리 못하고 있는 상태

Stack vs Heap 

Stack : 정적으로 할당된 메모리 영역 

원시 타입의 데이터가 값과 함께 할당, Heap 영역에 생성된 Object 타입의 데이터의 참조 값 할당 

Heap : 동적으로 할당된 메모리 영역 

모든 Object 타입의 데이터가 할당. Heap영역의 Object를 가리키는 참조 변수가 Stack에 할당

Reachable, Unreachable

HEAP 메모리의 ROOT SPACE

  • 1. STACK의 로컬 변수
  • 2. Method Area의 Static 변수
  • 3. Native Method Stack의 JNI 참조

의도적으로 GC 실행시키는 기준

Young VS Old generation 

두개를 나누어서 관리하는 이유 : 대부분의 객체가 수명이 짧기 때문에 짧은 객체를 minor GC로 따로 관리하는 것이 더욱 효율적. 

 

Young generation에서 발생하는 GC : Minor GC 

 

  • Minor GC : 비교적 시간이 짧고 간단. 

Old generation에서 발생하는 GC : Major GC

 

  • Major GC : 비교적 시간이 길고 복잡. 더 오랜시간 소요.

어플리케이션 실행과 GC 실행 병행 

GC를 실행하는 동안은 애플리케이션 동작이 멈춤 (Stop the world) 

  • GC의 역사 : Serial GC -> Parallel GC (java 8) -> CMS GC (메모리, CPU 과도사용) -> G1 GC 

Serial GC 

  1. 하나의 쓰레드로 GC를 실행 
  2. Stop The World 시간이 긺
  3. 싱글 쓰레드 환경 및 Heap이 매우 작을 때 사용

Parallel GC (java 8)

  1. 여러 개의 쓰레드로 GC를 실행
  2. 멀티 코어 실행.

CMS GC (메모리, CPU 과도사용) 

  1. 애플리케이션 쓰레드와 함께 구동
  2. 메모리 파편화 해결 모듈 기본 탑재 X 

G1 GC 

  1. Heap을 Region 으로 나누어 사용.
  2. 자동으로 Young generation 과 Old generation 비율을 최적화
  3. Java 9 부터 채택 

GC 튜닝을 위한 기초 내용 [참고]

GC 튜닝을 위해서는! 

1. Old Generation 으로 넘어가는 객체 최소화 
2. Major GC 시간을 짧게 유지. 

이 두가지가 필요하다. 

GC 상태 모니터링

어떤 GC를 채택하는지, 기본 Heap 사이즈 등 확인할 수 있는 방법.

java -XX:+PrintCommandLineFlags -version

-XX:InitialHeapSize=2147483648 
-XX:MaxHeapSize=32210157568 
-XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops 
-XX:+UseParallelGC
openjdk version "1.8.0_322"
OpenJDK Runtime Environment (Zulu 8.60.0.21-CA-linux64) (build 1.8.0_322-b06)
OpenJDK 64-Bit Server VM (Zulu 8.60.0.21-CA-linux64) (build 25.322-b06, mixed mode)

지금 구동되고 있는 GC상태를 확인하고자 한다면, jstat 사용. 

jstat -gcutil -t [PID] 1000 10 # 1초씩 10번

Timestamp         S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT
        60078.0   3.01   0.00  61.75  27.47  88.89  87.78  26072  305.462    37   12.251  317.713
        60079.0   0.00  99.88  98.99  27.49  88.89  87.78  26073  305.471    37   12.251  317.722
        60080.0  64.52   0.00  17.61  27.50  88.90  87.79  26074  305.482    37   12.251  317.733
        60081.0  64.52   0.00  37.78  27.50  88.90  87.79  26074  305.482    37   12.251  317.733
        60082.0  64.52   0.00  61.54  27.50  88.90  87.79  26074  305.482    37   12.251  317.733
        60083.0  64.52   0.00  92.99  27.50  88.90  87.79  26074  305.482    37   12.251  317.733
        60084.0   0.00  64.69  24.66  27.51  88.90  87.79  26075  305.494    37   12.251  317.745
        60085.0   0.00  64.69  48.97  27.51  88.90  87.79  26075  305.494    37   12.251  317.745
        60086.0   0.00  64.69  68.36  27.51  88.90  87.79  26075  305.494    37   12.251  317.745
        60087.0   0.00  64.69  88.96  27.51  88.90  87.79  26075  305.494    37   12.251  317.745

Young generation 영역부터 

s0 : Servivor-0

s1 : Servivor-1 

E : Eden 

O : Old generation 

YGC : Young generation 이벤트 수 

YGCT : Young generation GC Time 

즉, YGCT/YGC = minor GC 한번에 0.011초 소요

FGC : Full GC 이벤트 수 

FGCT : Full GC Time

즉, FGCT/FGC = major GC 한번에 0.32초 소요
GCT : 모든 가비지 컬렉션 총 시간 

 

만약 MAJOR GC의 시간이 오래걸려 DB Connection 시간이 일정시간을 넘어가게 된다면? : DB Connection timeout 시간초과로 장애의 원인이 될 수 있다. 

 

마찬가지로 GC가 할당받은 Heap Memory 를 확인하고자 한다면, jstat -gccapacity -t 924307 1000 10

jstat -gccapacity -t 924307 1000 10

Timestamp        NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC
        61073.5 698880.0 5592064.0 793088.0 265216.0 266240.0 257024.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26552    37
        61074.5 698880.0 5592064.0 805888.0 267776.0 266240.0 257024.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26553    37
        61075.5 698880.0 5592064.0 805888.0 267776.0 266240.0 257024.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26553    37
        61076.5 698880.0 5592064.0 805888.0 267776.0 266240.0 257024.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26553    37
        61077.5 698880.0 5592064.0 805888.0 267776.0 266240.0 257024.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26553    37
        61078.5 698880.0 5592064.0 800768.0 266240.0 265216.0 256000.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26555    37
        61079.5 698880.0 5592064.0 800768.0 266240.0 265216.0 256000.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26555    37
        61080.5 698880.0 5592064.0 803328.0 266240.0 266752.0 267776.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26556    37
        61081.5 698880.0 5592064.0 803328.0 266240.0 266752.0 267776.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26556    37
        61082.5 698880.0 5592064.0 803328.0 266240.0 266752.0 267776.0  1398272.0 11185152.0  2602496.0  2602496.0      0.0 1171456.0 139776.0      0.0 1048576.0  18176.0  26556    37

 

NG : Young generation 
OG : Old generation 
793MB / 2602MB 
CMN : 최소 할당 
CMX : 최대 할당 
C : 현재 할당

GC 메모리 튜닝을 위해서는 위 내용을 확인한 후 진행. 

1. Heap 크기 설정 
 - JVM 시작 시 힙 영역의 크기
 - 최대 힙 영역 크기

2. New 영역 크기 설정
 -XX:NewRatio 
  new 영역과 old영역의 비율
   -XX:NewRatio=1 NEW : OLD == 1:1 
   -XX:NewRatio=2 NEW : OLD == 1:2

 -XX:NewSize : New 영역의 크기
 -XX:SurvivorRatio : Eden 영역과 Survivor 영역의 비율

 

 

반응형
Comments