Java GC에 대해 알아보자
자바의 Execution Engine은 크게 3가지 주요 역할을 수행한다.
- JIT 컴파일러
- 인터프리터
- GC
이중 GC에 대해 알아보자.
우선 GC(Garbage Collection)은 자바의 메모리 관리 기법으로 jvm의 heap 메모리에 동적으로 할당된 객체들 중 쓰지 않는 객체들을 주기적으로 정리해 주는 프로세스이다.
Stop-The-World
GC가 동작하는 동안 다른 프로세스들이 멈추는 현상이다.
Stop-The-World 시간이 길어지면 GC관련 스레드를 제외한 나머지 스레드들의 동작이 멈추기 때문에
프로그램 동작에 차질이 생길 수 있다. 따라서 이 시간을 줄이는 것이 쟁점이다.
-> GC를 실행할 때마다 프로그램이 멈추는 현상이 발생하게 되므로 소프트웨어 성능 하락으로 이어질 수 있다. GC 실행 최소화시키는 것이 중요
Mark-And-Sweep
참조되고 있는 객체 (Reachable), 참조되지 않는 객체 (Unreachable)들을 찾아 참조되고 있지 않은 객체들을 정리(Sweep) 시켜주는 단계이다.
1. Root Space부터 탐색을 하여 각각 어떤 객체들을 참조하고 있는지를 마킹한다.
(Root Space란 힙 메모리 영역을 참조하고 있는 stack, native method stack, method area 영역이 있다.)
2. 마킹이 끝난 후 Unreachable 객체를 찾아 정리시켜 준다.
3. GC에 따라서는 Compaction이 일어나 heap의 시작 메모리 주소로 모아준다.
GC 동작 원리
Heap 메모리 영역은 크게 Young Generation과 Old Generation으로 나눠진다.
대부분의 객체들은 일회성으로 메모리에 할당된 후 금방 사용되지 않는다. 따라서 오랫동안 사용되는 객체들과 일회성 객체들을 효율적으로 관리하기 위해 Young Generation, Old Generation 영역으로 나눠서 관리한다.
Young Generation은 또다시 Eden영역과 Survivor영역으로 나뉜다.
처음 할당되는 객체들은 Eden 영역에 할당되고 GC에서 살아남은 객체들은 survivor 영역으로 보내지게 되는데, 이때 survivor영역은 1,2 두 개가 있다. 둘 중의 한 영역은 항상 비어있어야 한다.
Minor GC
Young 영역에서 일어나는 GC를 Minor GC라고 한다. Minor GC 특성상 크기가 작기 때문에 GC에 걸리는 시간이 적다.
Minor GC에서 살아남을 때마다 age가 증가하여 특정 age에 도달하면 Old 영역으로 보내진다.
Major GC
young 영역에서 살아남은 객체들이 old 영역으로 넘어오게 되고, 계속해서 넘어오다 보면 old 영역도 언제 가는 꽉 차게 될 것이다. 이때 일어나는 GC가 Major GC다.
Major GC는 old 영역의 크기가 크기 때문에 GC에 걸리는 시간이 young 영역에 10배 이상 더 걸린다.
따라서 old 영역에서의 GC가 일어날 때 Stop-The-World 시간이 길어지므로 문제가 생긴다.
이를 해결하기 위해 Java GC는 끊임없이 발전해 왔다.
이 중에서 Java 9+ 버전 이상에서 default GC로 사용되고 있는 G1 GC에 대해서 알아보자.
G1 GC
이전 GC처럼 힙 메모리를 Young, Old 영역으로 구분한다. 하지만 region이라는 개념을 도입했다.
이전 GC들처럼 영역이 고정되어 있지 않고, 동적으로 region을 부여할 수 있다. (Eden영역이 Old 영역으로 바뀔 수도 있음. 상황마다 동적으로 할당)
G1 GC의 효율성
- 힙 영역의 객체를 마킹할 때 같이 시간이 오래 걸리는 작업들은 애플리케이션과 병렬적으로 처리를 함.
- Stop-The-World 시간을 짧게 유지하기 위해 메모리 회수를 한 번에 하는 것이 아니라 점진적으로 처리함.
- 이전의 GC 결과와 힙 영역의 상황을 고려하여 IHOP(Initiating Heap Occupancy Percent)을 수정함. G1 GC는 IHOP에 따라서 Minor GC와 Mixed GC를 실행하므로 IHOP의 상태를 최적으로 수정하는 것이 중요!
Garbage Collection Cycle
- Young-Only 페이즈: old 객체를 새로운 공간으로 이동
- Space Reclamation 페이즈: 공간 회수
- old gen 점유율이 threshold값을 넘으면 young-only 페이즈로 전환된다.
- Concurrent Start에서는 객체들에 마킹 작업을 한다.
- Remark는 마킹을 종료하고, garbage 영역을 해지한다
- Cleanup 단계에서는 Space Reclamation 단계에 진입할지 결정한다.
- Space Reclamation 단계에서는 Mixed GC가 수행된다 -> young/old 객체들을 적절한 곳으로 대피시킨다. -> 끝난 후 young-only 페이즈로 전환
참고 자료
'Java, Spring' 카테고리의 다른 글
[트러블 슈팅] docker-compose로 브릿지 네트워크 구성 (0) | 2024.08.26 |
---|---|
Spring Security를 이용하여 JWT 토큰방식 로그인 구현 (0) | 2024.08.18 |
AOP를 이용한 분산락 구현 (0) | 2024.07.21 |
Spring AOP에 대해서 알아보자 (3) | 2024.07.13 |
무신사 블프 이벤트 상품 동시성 문제 (2) (0) | 2024.07.10 |