Garbage Collection (GC)
GC는 JVM에서 메모리 관리를 자동화하는 기능이다.
주요 목적은 다음과 같다.
- 메모리 관리 자동화
- 사용하지 않는 객체의 메모리를 자동으로 해제하여 메모리 누수를 방지한다.
- 개발자의 메모리 관리 부담을 줄일 수 있다.
- 안정성 향상
- 잘못된 메모리 해제, 이중 해제 등 메모리 관리와 관련된 버그를 줄일 수 있다.
- 메모리 최적화
- GC를 통해 메모리를 사용을 최적화하고 메모리 공간을 효율적으로 활용한다.
Heap 메모리 구조 (Young Generation과 Old Generation)
GC는 주로 Heap 영역을 대상으로 동작하며, Heap은 Young Generation과 Old Generation으로 나뉜다.
- Young Generation
- Eden : 새로 생성된 객체가 할당되는 영역
- Survivor : Minor GC에서 살아남은 객체가 이동하는 영역. S0, S1로 나뉨.
- Old Generation
- Young Generation에서 오래 살아남은 객체가 이동하는 영역
GC설계 원칙
- Generational Hypothesis
대부분의 객체는 짧은 생명 주기를 가지고, 오래 살아남은 객체는 더욱 오래 생존할 가능성이 높다는 가정을 바탕으로 한다. - Locality of Reference
최근에 생성된 객체는 서로 가까운 메모리 영역에 할당되는 경향이 있다.
이는 Young Generation에서의 객체 할당과 해제가 효율적으로 이루어지도록 한다.
위의 설계원칙에 기반하여 GC는 Young Generation과 Old Generation으로 나누어 동작하도록 설계되어있다.
Young Generation에서 발생하는 GC를 Minor GC, Old Generation에서 발생하는 GC를 Major GC라고 한다.
Minor GC
Young Generation에서 발생하는 GC.
위에서 언급했 듯이 Young Generation은 Eden space와 두개의 Survivor space (S0, S1)로 나뉜다.
먼저, 새롭게 생성된 객체는 Eden Space에 할당된다.
Eden Space가 가득 차게되면 Minor GC가 발생하게 된다.
이때, 참조되는 객체들은 S0 survivor space로 이동되고, 참조되지 않는 객체들은 Eden space에서 삭제된다.
다음 Minor GC가 발생하게 되면 Eden space에서는 앞에서 언급한 동작을 다시 반복한다.
하지만, 이때는 S0이 아닌 S1 survivor space로 이동한다.
S0에서도 마찬가지로, 참조되지 않은 객체들은 삭제되고 참조되는 객체들은 age를 증가 시킨 후 S1 survivor space로 이동한다.
이 과정이 끝나면 Eden space와 S0 survivor space는 모두 지워진 상태가 된다.
이후 Minor GC가 발생하며 이번엔 이동이 S0으로 바뀌며 동일한 작업을 반복한다.
이렇게 Survivor space를 번갈아 가며 작업이 이뤄지다, 오래된 객체가 특정 age 임계값에 도달하면 Old Generation으로 이동시킨다.
Major GC
Old Generation에서 일어나는 GC.
Minor GC가 계속 발생하면 Old Generation 영역에 계속해서 객체가 쌓이게 된다.
Old Generation 영역이 가득차게 도면 Major GC가 발생한다.
또는, 시스템 메모리가 부족해도 Major GC가 발생하게 된다.
Major GC는 Mark and Sweep 알고리즘을 사용한다.
- Mark 단계
모든 객체 그래프를 탐색하여 도달 가능한(reachable) 객체를 mark한다.
도달 불가능한(unreachable) 객체는 가비지로 간주된다. - Sweep 단계
도달 불가능한(unreachable) 객체를 메모리에서 제거하여 메모리 공간을 회수한다. - Compaction 단계
메모리 단편화를 줄이기 위해 메모리 영역을 압축한다.
객체를 한쪽으로 몰아 빈 공간을 연속적인 메모리 블록으로 만든다.
여기서 도달 가능/불가능은 GC 루트로부터 객체에 도달 가능 여부를 말한다.
특징
- Stop-the-World
GC가 발생하면, 애플리케이션의 모든 스레드가 잠시 멈춘다. - 발생 빈도: Minor GC > Major GC
Eden space가 자주 가득차기 때문에 Minor GC가 더 빈번하게 발생한다.
Minor GC에서 새로 생성되는 대부분의 객체가 삭제 되기 때문에 Old Generation은 덜 발생한다. - 동작 시간: Minor GC < Major GC
Major GC의 시간이 더 오래 걸리는 이유는 다음과 같다.
- Old Generation 영역의 크기가 더 크기 때문에 처리할 메모리 영역이 더 넓다.
- Old Generation의 객체는 긴 생명주기를 갖기 때문에 더 복잡하게 참조되어 있을 가능성이 커 정리과정이 더 복잡하다.
- mark and sweep, compacting 등의 알고리즘이 사용되어 더 많은 작업을 수행해야한다.
'Language > Java' 카테고리의 다른 글
Java의 스레드(Thread) (0) | 2024.12.10 |
---|---|
Error & Exception (1) | 2024.12.09 |
Inheritance와 Composition (클래스 간의 관계) (0) | 2024.12.07 |
오토박싱(Autoboxing)/언박싱(Unboxing) (0) | 2024.12.06 |
Promotion(자동형변환)과 Casting(명시적형변환), Upcasting vs Downcasting (0) | 2024.12.05 |