자바를 사용하면 메모리 해제를 가비지 컬렉터가 해준다고 알고 있긴하지만 정확히 언제, 어떻게 되는지에 대해서까지 알지는 못했다.
힙에 올라간 인스턴스를 해제하는 거긴할텐데... 어떻게 안쓰는지 확인하고 해제되는지 알아보도록 하자.
Garbage 판단
GC는 객체를 유효한 참조가 존재하면 Reachable, 참조가 없다면 Unreachable로 구분한다.
이 상태는 Root Set(Stack, Method, Native Stack)과 참조 관계로 판단한다.
방금 설명한 Root Set과 Reachable 유무로 Garbage Collector의 작동원리를 설명하면
1. Root Set으로부터 Heap 영역으로의 참조가 있는 Reachable 객체를 찾는다 > Mark
2. UnReachable객체를 Heap 영역에서 제거한다 > Sweap
GC 발생 시점
GC가 일어나는 시점을 알기위해선 Heap 영역의 구성요소를 알아야 한다.
JVM Heap Area
Heap 영역은 Young과 Old로 나뉘는데 이유는 다음과 같다.
1. 시간
영역을 나누지 않고 모든 객체를 추적하는 것은 많은 시간이 소요될 수 있다.
2. JVM GC 설계자들의 Weak generational hypothesis
대부분의 할당된 객체는 오랫동안 참조되지 않으며 금방 Unrechable 객체가 되고 오래된 객채에서 젊은 객체로의 참조는 거의 없다.
GC가 일어나는 시점을 위해 Heap 영역을 알아봤는데 사실 효율적인 GC를 위해 Heap 영역이 generational로 설계된 것 같다.
Minor GC, Major GC
Young generation은 Eden, Survivor1, Survivor2로 나뉜다.
1. 새로운 객체는 Eden 영역에 할당된다.
2. Eden영역이 꽉차면 Minor GC가 일어나 Mark and Sweep 과정이 일어나 Unreachable한 객체를 해제한다.
3. 살아남은 객체는 Survivor 영역으로 옮겨진다.(Stop and Copy) 옮겨진 객체의 age는 1 증가한다.
4. 또 Eden 영역이 꽉찬다면 Minor GC가 발생한다.
살아남은 객체는 Survivor 영역으로 옮겨진다.(Stop and Copy) 옮겨진 객체의 age는 1 증가한다.
단편화 문제를 해결하기 위해 비어있는 Survivor로 이동한다.
5. 1~4가 반복되고 Survivor의 객체의 age가 특정값 이상이 되면 Old generation으로 이동한다(Promotion)
HotSpot JVM Default 임계값은 31이다.
6. 이후 Old Generation이 꽉 차면 Major GC가 발생한다.
GC가 중요한 이유
Stop The World
GC 진행은 GC를 실행하기 위한 Thread를 제외한 모든 Thread는 멈추고 GC가 완료 된 이후에 다시 Thread가 진행되기 때문에 심각한 애플리케이션의 장애로 이어질 수 있어 GC의 원활한 관리가 시스템의 안정성에 큰 축을 담당한다.
JAVA Version에 따른 GC 종류
JAVA 8 이전까지는 Paralle GC가 Default였지만 JAVA 9부터는 G1GC가 Default로 설정되어있다.
G1GC는 전통적이고 물리적으로 구분된 Heap 영역과 달리 위 그림과 같이 논리적으로 Heap 영역을 나눠 구분한다.
참조