JVM의 Heap 영역에서 사용하지 않는 객체를 삭제하는 프로세스
*Heap : 동적으로 할당한 메모리 영역
모든 Object 타입의 데이터가 할당, Heap 영역의 Obejct를 가리키는 참조 변수가 Stack에 할당
*Stack : 정적으로 할당한 메모리 영역
원시 타입의 데이터가 값과 함께 할당, Heap 영역에 생성된 Obeject 타입의 데이터의 참조 값 할당
Java 프로세스가 동작하는 과정에서 GC는 불필요한 또는 더이상은 사용하지 않는 객체들을 메모리에서 제거함으로써, Java 프로세스가 한정된 메모리를 효율적으로 사용할 수 있게 해준다.
또한 JVM에서 GC의 스케줄링을 담당함으로서 Java 프로그래머들에게는 메모리를 관리해야하는 부담을 줄여주게된다. 즉, 일반적인 개발 작업간에는 메모리 할당/해제를 직접 프로그래밍하지 않아도 된다.
현재 열심히 사용중인 객체를 메모리에서 제거해버린다면, 프로그램이 정상적으로 실행되지 않을 것이다. 때문에, GC를 위해서는 우선 메모리에 있는 객체가 현재 사용중인지 사용중이 아닌지를 구분할 수 있어야한다.
새로 생성된 대부분의 객체는 Eden 영역에 위치한다.
Eden 영역이 꽉 차게 되면 GC가 발생한다. GC가 발생한 이후, 살아남은 객체는 Suvivor 영역 중 하나로 이동한다.
이 과정을 반복하다가 계속해서 살아남은 객체는 일정 시간 참조되고 있다는 뜻이므로 Old 영역으로 이동한다.
Old 영역에 있는 모든 객체들을 검사하여 참조되고 있지 않은 객체들을 한꺼번에 삭제한다.
시간이 오래 걸리고 실행 중 프로세스가 정지된다. 이것은 'Stop-the-World'라고 하는데, Major GC가 발생하면 GC를 실행하는 스레드를 제외한 나머지 스레드는 모두 작업을 멈춘다. GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다.
GC의 튜닝은 이 'Stop-the-World'의 시간을 줄이는 것이다.
mark -> GC는 GC Roots로 부터 모든 변수를 스캔하면서 각각 어떤 객체를 참조하고 있는지 찾아서 마킹
Sweep -> Unreachable 객체들을 Heap에서 제거
+Compact -> Sweep 후에 분산된 객체들을 Heap의 시작 주소로 메모리가 할당된 부분과 그렇지 않은 부분으로 나눔.
알고리즘에 따라 동작 방식이 매우 다양하지만 공통적인 원리가 있다.
Garbage Collector는 힙 내의 객체 중에서 가비지를 찾아내고 찾아낸 가비지를 처리해서 힙의 메모리를 회수한다.
참조되고 있지 않은 객체를 가비지라고 하며, 객체가 가비지인지 아닌지 판단하기 위해서 Reachability라는 개념을 사용한다.
어떤 힙 영역에 할당된 객체가 유효한 참조가 있으면 Reachability, 없다면 UnReachability로 판단한다.
하나의 객체는 다른 객체를 참조하고 다른 객체는 또 다른 객체를 참조할 수 있기 때문에 참조 사슬이 형성된다. 이 참조 사슬 중 최초에 참조한 것을 Root Set이라고 한다.
힙 영역에 있는 객체들은 총 4가지 경우에 대한 참조를 하게 된다.
유효한 최초의 참조가 이루어지지 않은 객체들은 Unreachable Objects로 판단하며, GC에 의해 수거된다.
인스턴스가 가비지 컬렉션의 대상이 되었다고 해서 바로 소멸이 되는 것은 아니다. 빈번한 가비지 컬렉션의 실행은 시스템에 부담이 될 수 있기 때문이다. 그래서 성능에 영향을 미치지 않도록 가비지 컬렉션 실행 타이밍은 별도의 알고리즘을 기반으로 계산이 되며, 이 계산 결과를 바탕으로 GC가 수행된다.
참고자료
https://mirinae312.github.io/develop/2018/06/04/jvm_gc.html,
https://github.com/WooVictory/Ready-For-Tech-Interview/blob/master/Java/%5BJava%5D%20Garbage%20Collection.md