자바는 가비지 콜렉션 기능을 이용해 메모리 관리의 효율성을 제공합니다.
자바의 가비지 콜렉션은 'weak generational hypothesis' 이론에 기반합니다. 이는 신규로 생성한 객체의 대부분은 금방 사용하지 않는 상태가 되고, 오래된 객체에서 신규 객체로의 참조는 매우 적게 존재한다는 것입니다. 이 이론에 기반하여 자바는 Young 영역과 Old 영역으로 메모리를 분할하고, 신규로 생성되는 객체는 Young 영역에 보관하고, 오래동안 살아남은 객체는 Old 영역에 보관합니다.
Young 영역은 Eden, S0, S1 영역으로 구분됩니다. 신규로 생성되는 객체는 Eden에 보관되고, Eden 영역이 100% 차게 되면 사용하지 않는 객체는 제거하고 사용되는 객체는 S0 영역으로 이동합니다. 이를 마이너 GC라고 합니다. 다시 Eden 영역에 신규로 생성되는 객체가 보관되고, Eden 영역이 100%가 되면 Eden 영영과 S0영역에서 사용하지 않는 객체는 제거하고, 남은 객체는 S1 영역으로 이동합니다. 이 또한 마이너 GC입니다. 이 작업을 반복하면서 오래동안 살아 남은 객체는 Old 영역으로 이동하게 됩니다. 마이너 GC는 JVM을 멈추지 않고 진행 합니다.
마이너 GC에서 Young영역에서 Old 영역으로 이동하는 기준이 되는 값은 -XX:MaxTenuringThreshold 옵션으로 설정합니다. 이 설정값을 넘어가면 Young 에서 Old 영역으로 이동합니다.
Old 영역에 마이너 GC의 결과로 살아 남은 객체들이 보관되다가 Old영역이 100%가 되면 메이저 GC(Full GC)가 발생합니다. JVM의 동작을 멈추고 Old 영역의 메모리를 정리하게 됩니다. 메이저 GC가 발생하면 프로그램의 동작이 멈추기 때문에 메이저 GC의 발생과 처리시간을 줄이는 것이 중요합니다.
GC 설정
GC를 처리하는 방식을 설정하는 방법은 다음과 같습니다. XX 옵션을 이용하여 프로그램 실행시점에 처리 방식을 설정할 수 있습니다.
# GC 방법 설정
$ java -Xmx1000m -XX:+UseConcMarkSweepGC
GC 처리 방식
- -XX:+UseSerialGC: 하나의 스레드를 이용하여 Young 영역과 Old 영역의 정리를 처리
- -XX:+UseParallelGC: Young 영역의 정리에 다수의 스레드를 이용하여 처리
- -XX:+UseParallelOldGC: Old 영역의 처리도 다수의 스레드를 이용하여 처리
- -XX:+UseConcMarkSweepGC: 메이저 GC의 성능 향상을 위해 Old 영역의 정리를 Concurrent 방식으로 처리
GC 모니터링
GC 모니터링은 jstat
을 이용합니다. 상세한 설정 및 설명은 오라클 홈페이지에서 확인 바랍니다. jstat
을 이용하는 방법은 다음과 같습니다.
$ jstat [유틸옵션] [PID] [반복 출력 시간]
# PID 129의 정보를 1초(1000)마다 반복 출력
$ jstat -gcutil 129 1000
jstat 옵션
- class: 클래스 로더의 통계정보 출력
- compiler: JIT 컴파일러의 통계정보 출력
- gc: GC힙의 통계정보 출력
- gccapacity: 힙의 용량(capacity) 정보를 출력
- gccause: GC 통계정보와 GC가 발생한 원인 출력
- gcnew: new 영역의 정보 출력
- gcnewcapacity:new 영역의 용량 정보 출력
- gcold: old 영역과 meta 영역의 정보 출력
- gcoldcapacity:old 영역의 용량 출력
- gcmetacapacity:meta 영역의 용량 출력
- gcutil: GC 통계정보 쳘력
- printcompilation:컴파일 메소드 정보 출력
jstat 예제
각 옵션별 처리 결과는 다음과 같습니다.
$ jstat -class 16973
Loaded Bytes Unloaded Bytes Time
11589 23339.2 152 220.6 5.18
$ jstat -compiler 16973
Compiled Failed Invalid Time FailedType FailedMethod
22084 3 0 115.46 1 sun/misc/URLClassPath getResource
$ jstat -gc 16973
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
8000.0 8000.0 0.0 807.7 64512.0 26615.7 161152.0 61238.5 76768.0 75677.1 7932.0 7654.6 38831 95.958 10 0.219 96.178
$ jstat -gccapacity 16973
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
80512.0 341312.0 80512.0 8000.0 8000.0 64512.0 161152.0 682688.0 161152.0 161152.0 0.0 1118208.0 76768.0 0.0 1048576.0 7932.0 38831 10
$ jstat -gccause 16973
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
0.00 10.10 41.26 38.00 98.58 96.50 38831 95.958 10 0.219 96.178 Allocation Failure No GC
$ jstat -gcmetacapacity 16973
MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC FGCT GCT
0.0 1118208.0 76768.0 0.0 1048576.0 7932.0 38831 10 0.219 96.178
$ jstat -gcnew 16973
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
8000.0 8000.0 0.0 807.7 6 6 4000.0 64512.0 26615.7 38831 95.958
$ jstat -gcnewcapacity 16973
NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC
80512.0 341312.0 80512.0 34112.0 8000.0 34112.0 8000.0 273088.0 64512.0 38831 10
$ jstat -gcold 16973
MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
76768.0 75677.1 7932.0 7654.6 161152.0 61238.5 38831 10 0.219 96.178
$ jstat -gcoldcapacity 16973
OGCMN OGCMX OGC OC YGC FGC FGCT GCT
161152.0 682688.0 161152.0 161152.0 38831 10 0.219 96.178
$ jstat -gcutil 16973
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 10.10 41.26 38.00 98.58 96.50 38831 95.958 10 0.219 96.178
$ jstat -printcompilation 16973
Compiled Size Type Method
22084 626 1 sun/reflect/GeneratedMethodAccessor93 invoke
gcutil 예제
jstat -gcutil
을 이용하면 현재 Young 영역과 Old 영역의 메모리 사용률을 확인할 수 있습니다.
- S0 : S0 영역 사용율
- S1 : S1 영역 사용율
- E : Eden 영역 사용율
- O : Old 영역 사용율
- M : Meta 영역 사용율
- CCS : Compressed Class Space 영역 사용율
- YGC : Young 영역 GC 횟수
- YGCT : Young 영역 GC에 걸린 시간
- FGC : Full GC 횟수
- FGCT : Full GC에 걸린 시간
- GCT : GC에 걸린시간(YGCT + FGCT)
# PID 16973의 GC 상황을 1초(1000)마다 한번씩 출력
$ jstat -gcutil 16973 1000
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
97.46 0.00 21.86 99.55 98.68 96.82 3548 166.537 3 1.449 167.987
97.46 0.00 60.18 99.55 98.68 96.82 3548 166.537 3 1.449 167.987
97.46 0.00 96.35 99.55 98.68 96.82 3548 166.537 3 1.449 167.987
0.00 98.61 30.60 99.73 98.68 96.82 3549 166.620 3 1.449 168.069
0.00 98.61 67.84 99.73 98.68 96.82 3549 166.620 3 1.449 168.069
97.25 0.00 0.00 99.94 98.68 96.82 3550 166.702 4 1.449 168.152
0.00 0.00 22.28 3.73 98.61 96.69 3550 166.702 4 1.813 168.516
0.00 0.00 57.87 3.73 98.61 96.69 3550 166.702 4 1.813 168.516
0.00 0.00 93.27 3.73 98.61 96.69 3550 166.702 4 1.813 168.516
참고
JVM 메모리 구조와 JAVA OPTION 값 정리
Java jstat로 메모리 모니터링
Java GC의 원리
Java 의 GC는 어떻게 동작하나?
[JAVA] JVM GC 튜닝 정리중..
Garbage Collection 모니터링 방법
Garbage Collection 튜닝
JVM Internal
Java Garbage Collection
JAVA8 Permanent 영역은 어디로 가는가
오랜만에 Garbage Collection 정리
JVM의 Garbage Collection
JDK8 적용 후, 심각한 성능저하가 발생한다면?
JAVA Garbage Collection의 기초
JVM Internal
Java HotSpot Garbage Collection
'java' 카테고리의 다른 글
[java] JVM이란? (0) | 2019.07.08 |
---|---|
[java] 메모리 누수와 힙 덤프 분석 (0) | 2019.06.05 |
[Java] JVM 메모리 구조 및 옵션 (0) | 2019.06.04 |
[java] 자바 가상 머신(JVM : Java Virtual Machine) (0) | 2019.06.03 |
[java] Executor 클래스를 이용한 멀티 스레드 실행 예제 (0) | 2019.04.19 |