오늘은 자바의 Garbage Collection에 대해 정리해보려 한다.
자바는 메모리 해제를 위해 Garbage Collection(GC)을 사용한다. GC로 인해 개발자는 메모리 해제를 신경쓰지 않아도 되며, 명시적으로 메모리를 해제하려 하면 오히려 성능의 저하를 불러오게 된다.
GC는 아래와 같은 두 개의 가정 하에 만들어졌다.
1. 대부분의 객체는 곧 접근 불가능한 상태가 된다.
2. 오래된 객체에서 새로운 객체로의 참조는 거의 일어나지 않는다.
이러한 가설을 weak generational hypothesis라 하며, 이에 따라 자바의 hotspot GM은 매번 힙의 모든 영역을 검사하지 않고 일부 영역만 검사할 수 있도록 힙을 세 개의 영역으로 나누고, 영역에 따라 Minor GC와 Major GC를 실행하도록 했다.
1. Young Generation 영역
이 영역은 다시 3개의 영역 eden, S0(Survivor 0), S1(Survivor 2)로 나뉜다. 새로 생성된 객체는 eden 영역에 저장되며, 이 영역에서는 Minor GC 가 발생한다.
Minor GC가 끝난 뒤 아직 남아있는 객체들은 S0 또는 S1 영역으로 이동한다. 둘 중 하나의 영역이 다 찰 때까지 한 곳에만 객체들이 저장되며, 영역이 꽉 차게 되면 다시 GC를 실행하고 살아남은 객체는 반대쪽 Survivor 영역으로 이동시킨 뒤 원래의 Survivor 영역은 빈 상태가 된다. 이 과정을 계속 반복하면서 오랫동안 살아있는 객체는 Old Generation 영역으로 옮겨지게 된다.
Old Generation 영역으로 이동하는 기준은 각 객체에 저장된 age 비트이다. Minor GC가 발생할 때마다 age 비트가 1 씩 증가하며, age 비트 값이 MaxTenuringThreshold 값을 초과하면 Old Generation 영역으로 객체가 이동한다. 또는 age 비트가 이 값을 초과하지 않더라도 survivor 영역의 메모리가 부족할 경우 미리 Old 영역으로 이동할 수 있다.
2. Old Generation 영역
비교적 오래 살아있는 객체가 저장되는 영역이다. 이 영역에서는 Major GC가 발생한다. 이 영역은 일반적으로 Young Generation 영역보다 크다. 따라서 GC에 걸리는 시간이 늘어나고, 이 시간 동안에는 애플리케이션의 작동이 멈추게 된다. 이러한 시간을 stop-the-world(STW)라 한다. GC의 성능은 STW를 얼마나 줄일 수 있느냐로 정해지게 된다.
크게 다섯 가지의 Major GC 기법이 존재한다.
1. Serial GC
- CPU 코어가 하나만 있을 때를 위한 방식이므로 성능이 떨어진다. 따라서 운영 서버에서는 사용을 권장하지 않는다.
- mark-sweep-compact라는 알고리즘을 사용한다.
1. Old 영역의 살아있는 객체 식별(mark)
2. 힙의 앞부분부터 확인하면서 살아있는 객체만 남김(sweep)
3. 힙에 각 객체가 연속되게 쌓이도록 압축(compaction)
2. Parallel GC
- Serial GC와 기본적인 방식은 동일하지만, 여러 개의 쓰레드를 이용해 GC를 수행한다.
- Serial GC보다 빠른 속도
- CPU 코어 갯수가 많고 메모리가 충분할 때 좋은 방법이다.
Parallel GC의 속도가 더 빠르다는 것은 STW 시간이 줄어든다는 것을 의미하고, 이를 통해 Parallel GC의 성능이 Serial GC보다 좋다는 것을 알 수 있다.
3. Parallel Old GC
- Mark-Sweep-Compaction 단계 대신 Mark-Summary-Compaction 단계를 거친다.
- Summary 단계는 이미 GC가 수행된 영역에서 살아있는 객체를 탐지한다. 이 점이 매번 전체 힙 영역을 검사하는 sweep과는 다른 점이다.
4. Concurrent Mark & Sweep GC(CMS)
- Initial mark - Concurrent mark - Remark - Concurrent sweep 단계를 거친다.
Initial mark
클래스 로더와 가장 가까이 있는 살아있는 객체 하나만 탐지한다. 이를 통해 STW 시간을 단축할 수 있다.
Concurrent mark
Initial mark 단계에서 탐지한 객체에서 참조중인 객체를 따라가며 확인한다. 이 단계는 다른 스레드와 동시에 진행된다.
Remark
concurrent 단계에서 새로 추가되거나 참조가 끊긴 객체를 확인한다.
Concurrent sweep
가비지를 정리하는 작업을 실행한다. 이 단계도 다른 스레드와 동시에 진행된다.
이처럼 STW 시간이 여러 구간으로 나누어져 있고, 다른 스레드와 동시에 진행되는 단계가 많으므로 parallel GC에 비해 STW 시간이 짧다. 이러한 특성으로 인해 CMS GC는 Low-Latency GC라고도 불린다. 따라서 애플리케이션의 응답 속도가 매우 중요한 곳에서 사용한다.
CMS GC의 단점은 다른 GC보다 하는 일이 많기 때문에 메모리와 CPU를 더 많이 사용하고, Compaction 단계가 제공되지 않아 메모리 단편화가 발생할 수 있다.
5. G1(Garbage First) GC
- CMS GC를 대체하기 위해 등장
- 힙을 region이라는 바둑판 영역으로 공간을 나눠 객체를 할당하고 GC를 실행한다.
- region의 크기는 힙을 2,048개로 나눌 수 있을 정도로 결정됨.
- 영역이 꽉차면 다른 영역에 객체를 할당하고 GC를 수행함.
- GC 대상은 살아있는 객체가 가장 적게 들어있는 region
- 장점 : STW 시간이 짧고 예측 가능하다.
3. Permanent Generation 영역
클래스, 메소드와 같은 코드가 저장되는 영역으로, JVM에 의해 사용된다.
참조한 사이트
1. d2.naver.com/helloworld/1329 - Java Garbage Collection
2. asfirstalways.tistory.com/159 - #가비지 컬렉션(Garbage Collection) / JVM 구동 원리에 이어서
이미지 출처
1. javarevisited.blogspot.com/2011/05/java-heap-space-memory-size-jvm.html#axzz6jtJxbR4g - Java heap structure
2. www.techpaste.com/2012/02/java-garbage-collectors-gc/ - java garbage collector comparison
3. www.dehinsystems.com/understanding-java-garbage-collection/ - Serial GC & CMS GC
4. www.oracle.com/technetwork/tutorials/tutorials-1876574.html - G1 GC
'Java' 카테고리의 다른 글
Optional 클래스 (0) | 2021.01.06 |
---|