학습 기록 블로그
[Java] 가비지 컬렉션(GC,Garbage Collection) 본문
Java의 메모리 관리법 중 하나인 가비지 컬렉션(GC) 학습을 위해 내용을 정리해보고자 한다.
1. 가비지 컬렉션이란?
GC라고도 불리는 가비지 컬렉션은 자바의 메모리 관리법 중의 하나로 JVM의 Heap 영역에서 동적으로 할당했던 메모리 영역 중 필요 없게 된 메모리 영역(메모리 객체)을 주기적으로 삭제하는 프로세스를 말합니다. C나 C++에서는 free()라는 함수를 통해 개발자가 수동으로 메모리 할당과 해제를 해주어야 하는 반면 Java에서는 JVM에 탑재되어 있는 가비지 컬렉터가 메모리 관리를 주기적으로 대신 해주기 때문에 개발자가 완벽하게 관리하지 않아도 된다는 장점이 있습니다.
2. 가비지 컬렉션 단점
메모리 관리를 자동으로 해준다 해도 메모리가 언제 해제되는지 정확하게 알 수 없어 제어하기 어렵고, 가비지 컬렉션이 동작하는 동안에는 다른 동작이 멈추기 때문에 오버헤드가 발생되는 문제점이 있습니다.
이를 STW(Stop-The-World)라 합니다.
STW
=> GC를 수행하기 위해 JVM이 프로그램 실행을 멈추는 현상을 의미.
GC가 작동하는 동안 GC관련 Thread를 제외한 모든 Thread는 멈추게 되어 서비스 이용에 차질이 생길 수 있기 때문에 이 시간을 최소화 시키는 것이 중요합니다.
3. 가비지 컬렉션 대상
가비지 컬렉션은 특정 객체가 garbage인지 아닌지 판단하기 위해서 도달성, 도달능력 이라는 개념을 적용합니다.
객체에 레퍼런스가 있다면 Reachable로 구분되고, 객체에 유효한 레퍼런스가 없다면 unreachable로 구분하고
수거합니다.
Reachable => 객체가 참조되고 있는 상태
Unreachable = > 객체가 참조되고 있지 않은 상태 (GC의 대상)
JVM 메모리에서 객체들은 실질적으로 Heap영역에서 생성되고 Method Area나 Stack Area 에서는 Heap Area에 생성된 객체의 주소만 참조하는 형식으로 구성됩니다.
4. 가비지 컬렉션 작동 방식
Mark And Sweep 알고리즘
STW를 통해 모든 작업이 중단되면, GC는 스택의 모든 변수 또는 Reachable 객체를 스캔하면서 각각이 어떤 객체를 참고하고 있는지를 탐색합니다. 그렇게 사용되고 있는 메모리를 식별하는데, 이러한 과정을 Mark라 하고, 이후에 Mark가 되지 않은 객체들을 메모리에서 제거하는데, 이것을 Sweep이라고 합니다.
Sweep과정 완료 이후에 분산된 객체들을 Heap의 시작 주소로 모아 메모리가 할당된 부분과 그렇지 않은 부분으로 압축하는데 이과정을 Compaction이라고 합니다.
GC의 대상이 되는 Heap 영역
JVM의 Heap영역은 동적으로 레퍼런스 데이터가 저장되는 공간으로서, 가비지 컬렉션에 대상이 되는 공간입니다.
Heap영역은 처음 설계될 때 다음의 2가지를 전제(Weak Generational Hypothesis)로 설계되었습니다.
- 대부분의 객체는 금방 접근 불가능한 상태(Unreachable)가 된다.
- 오래된 객체에서 새로운 객체로의 참조는 아주 적게 존재한다.
즉, 객체는 대부분 일회성이며, 메모리에 오랫동안 남아있는 경우는 드물다는 것 입니다.
그렇기 때문에 생존 기간에 따라 물리적인 Heap 영역을 나누게 되었고 Young, Old 총 2가지 영역으로 설계되었습니다.
초기에는 Perm 영역이 존재하였지만 Java8부터 제거되었습니다.
Young 영역(Young Generation)
- 새롭게 생성된 객체가 할당(Allocation)되는 영역
- 대부분의 객체가 금방 Unreachable 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라진다.
- Young 영역에 대한 가비지 컬렉션을 Minor GC라고 부른다.
Old 영역(Old Generation)
- Young영역에서 Reachable 상태를 유지하여 살아남은 객체가 복사되는 영역
- Young 영역보다 크게 할당되며, 영역의 크기가 큰 만큼 가비지는 적게 발생한다.
- Old 영역에 대한 가비지 컬렉션(Garbage Collection)을 Major GC 또는 Full GC라고 부른다.
Eden
- new를 통해 새로 생성된 객체가 위치.
- 정기적인 쓰레기 수집 후 살아남은 객체들은 Survivor 영역으로 보냄
Survivor 0 / Survivor 1
- 최소 1번의 GC 이상 살아남은 객체가 존재하는 영역
- Survivor 0 또는 Survivor 1 둘 중 하나에는 꼭 비어 있어야 한다.
Minor GC 과정
Young Generation 영역은 짧게 살아남은 메모리들이 존재하는 공간으로 모든 객체는 처음 Young Generation에 생성되게 됩니다. Young Generation의 공간은 Old Generation 에 비해 상대적으로 작기 때문에 메모리 상의 객체를 찾아 제거하는데 적은 시간이 걸립니다. 이 때문에 Young Generation 영역에서 발생되는 GC를 Minor GC라고 부릅니다.
Young 영역의 Minor GC의 동작과정을 순차적으로 보자면
- 객체가 새롭게 생성되면 Young 영역 중 Eden 영역에 할당됩니다.
- 이후에 Eden 영역이 꽉차게 되면 Minor GC가 실행됩니다.
- Eden 영역에서 사용되지 않는 객체의 메모리가 해제됩니다.
- Eden 영역에서 살아남은 객체는 1개의 Survivor 영역으로 이동됩니다. - 1~2 번의 과정이 반복되다가 Survivor 영역이 가득 차게 되면 Survivor 영역의 살아남은 객체를 다른 Survivor 영역으로 이동시킨다.(1개의 Survivor 영역은 반드시 빈 상태가 된다.)
- 살아남은 객체의 age(살아남은 횟수)가 임계값에 도달하면 그 객체들을 Old Generation 으로 이동시키는데, 이를promotion이라 부릅니다.
Major GC 과정
Young 영역에서 오래 살아남은 객체는 Old 영역으로 Promotion되는데, 이 Promotion된 객체들에 의해 Old 영역의 메모리가 부족해지면 Major GC가 발생하게 됩니다. Young 영역은 일반적으로 Old 영역보다 크기가 작기 때문에 GC가 보통 0.5~1초 사이에 끝나는데, 이 때문에 Minor GC는 애플리케이션에 크게 영향을 주지 않습니다. 하지만 Old 영역은 Young 영역보다 크며 Young 영역을 참조할 수도 있기 때문에 Major GC는 Minor GC보다 평균적으로 10배 이상의 시간을 소요합니다.
참고자료)
[Java] 가비지 컬렉션 동작 원리 & GC종류 총정리
'Java' 카테고리의 다른 글
Java 구동 원리 및 JVM(Java Virtual Machine) (0) | 2023.02.07 |
---|