"GC는 자동적으로 동작하는데 왜 알아야 할까?" 라고 생각 할수 있지만 GC 이해 없이 코딩을 할 경우 성능이슈가 생기고 값비싼 수업료를 내야 할 수도 있다.
Heap 영역에 있는 객체들에 대한 참조의 종류는 4가지다.
1) Heap 내의 다른 객체에 의한 참조
2) JVM Stack, 즉 Java 메서드 실행 시에 사용하는 지역 변수와 파라미터들에 의한 참조
3) Native Stack, 즉 JNI(Java Native Interface)에 의해 생성된 객체에 대한 참조
4) Method Area의 static 변수에 의한 참조
이들 중 Heap 내의 다른 객체에 의한 참조를 제외한 나머지 3개(JVM Stack, Native Stack, Method Area)가 Root set으로 Reachability를 판가름 하는 기준이 된다. 즉, root set으로 부터 시작한 객체들은 reachable이며, root set과 무관한 객체들이 unreachable 객체로 GC의 대상이 된다.
그다음 Sweep는 Unreachable한 객체를 Heap에서 제거한다.
Heap 메모리는 Young Generation, Old Generation, Permanent Generation 영역으로 구분되고 Young Generation은 새로 할당된 객체들이 포함되어 있고, Old Generation은 Young Generation에서 살아남은 객체들이 해당 영역으로 이동된다.
GC 동작 과정
Step 1 : 새로 객체들이 Eden 영역에 할당된다.
Step 2 : Eden 영역이 다 채워지면 'Minor Garbage Collection'이 발동 된다.
Step 3 : 살아남은 객체들은 Survivor 영역 중 한 곳으로 이동되고 나머지 객체들은 제거 된다.
Step 4 : 다음번 Minor GC 가 발생하면 살아남은 객체들은 비어 있는 Survivor 영역(s1)으로 이동하고 Eden과 s0 영역은 빈 상태가 된다. 그리고 살아남은 객체들은 Minor GC가 발동 될때마다 나이르 먹게 된다.(s0, s1 영역의 Referenced object 들에 번호가 매겨진 것을 볼수 있다.)
Step 5 : Minor GC가 발생하고 객체들의 'Age' 값이 특정 임계점에 도달하면 Old Generation(Tenured) 영역으로 이동(Promotion)한다.
Step 6 : 마지막으로 Old generation 영역 마저 객체들로 다 채워지면 Old Generation 영역에 'Major GC'이 발동 하고 해당역역을 비워 준다.
Generation별로 GC하는 이유
GC 설계당시 다음 두 가지 가설(Weak Generation Hypothesis)을 고려하여 GC를 만들었다
그래서 Heap에 있는 모든 객체들을 'Mark', 'Compact' 하는것은 효율성이 떨어지고 Garbage Collecting 시간이 길어지니 Generation 별로 메모리가 찼을 때에만 Minor GC 또는 Major GC를 발생 시켜 Stop the world 소요 시간을 줄일수 있다.
6. Stop the world Event
GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것.
GC를 실행하는 쓰레드 외의 모든 쓰레드가 작업을 중단한다.
*보통 GC 튜닝이라고 하면 이 Stop the world 시간을 줄이는 것을 의미한다.
참고문서
https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html
https://www.oracle.com/technetwork/tutorials/tutorials-1876574.html
https://www.w3resource.com/java-tutorial/garbage-collection-in-java.php
https://d2.naver.com/helloworld/1329
https://sehun-kim.github.io/sehun/JVM/