GC Part.1
Last updated
Last updated
참고 링크
-> HotSpot JVM 은 오라클에서 개발한 JVM 구현체 중 하나이다.
GC 를 실행하기 위해서 JVM 이 애플리케이션 실행을 멈추는 것을 의미한다.
stop-the-world 가 발생하면 GC 를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다. -> GC 작업이 완료된 이후 중단했던 작업을 다시 시작한다.
어떤 알고리즘을 사용해도 stop-the-world 는 발생하고, GC 튜닝이란 stop-the world 시간을 줄이는 것이다.
Java 에서는 개발자가 프로그램 코드로 메모리를 명시적으로 해제하지 않기 때문에, GC 가 더 이상 필요 없는 객체를 찾아 지우는 작업을 한다. -> heap 영역에 해당! -> JVM 이 담당하는 작업으로 메모리 해제 타이밍을 정확하게 알지 못한다.
GC 는 다음 두 가설에 의해서 만들어졌다.
대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다. -> 대부분의 객체가 일시적으로 사용되고 GC 에 대상이 된다는 관찰 결과에 따른 내용
오래된 객체에서 젊은 객체로의 참조는 아주 드물게 존재한다.
결국 GC 도 비용이 드는 작업인데, 메모리 전체 부분이 아닌 특정 부분만을 탐색(Mark)하여 해제(Sweep)해야 효율적이다.
이러한 가설의 장점을 최대한 잘 살리기 위해서 HotSpot VM(JVM 구현체 중 하나) 에서는 Heap 영역을 크게 2개로 물리적 공간을 나누었다.
Young 영역 : 새롭게 생성한 객체 대부분이 위치하는 공간으로 대부분의 객체가 금방 사용하지 않는 상태가 되기 때문에, 매우 많은 객체가 Young 영역에 생성되었다가 사라진다. -> 해당 영역에서 일어나는 GC 를 Minor GC 가 발생한다고 말한다.
Old 영역 : Young 영역에서 살아남은(객체를 계속 사용하는 상태) 객체가 복사되는 공간이다. -> 대부분 Young 영역보다 크게 할당하고, 크기가 큰 만큼 Young 영역보다 GC 는 적게 발생한다. -> 해당 영역에서 일어나는 GC 를 Major GC가 일어난다 말한다.
위 그림의 Permanent Generation(자바8 부터 metaspace 라고 부른다) 영역은 Method Area(클래스 수준의 정보를 저장하는 영역) 이라고 한다.
Permanent Generation 영역은 Old 영역에서살아남은 객체가 영원히 남아있는 곳은 아니다. 이 영역에서도 GC 가 발생할 수 있는데, 여기서 GC 가 발생해도 Major GC 횟수에 포함된다.
"Old 영역에 있는 객체가 Young 영역의 객체를 참조하는 경우가 있을 때 어떻게 처리가 될까?" 라는 상황을 처리하기 위해서 Old 영역에는 512 바이트에 덩어리(chunk) 로 되어 있는 카드 테이블(card table) 이 존재한다.
카드 테이블에는 Old 영역에 있는 객체가 Young 영역의 객체를 참조할 때마다 Young 영역 객체에 해당하는 카드테이블이 체크된다. Young 영역의 GC 를 실행할 때는 Old 영역에 있는 모든 객체의 참조를 확인하지 않고 이 카드 테이블만 뒤져서 체크 되어있을 경우, GC 대상에서 제외한다.
Young 영역은 다음 3개의 영역으로 나뉜다.
Eden 영역
Survivor 영역
각 영역의 처리 절차 순서에 따라서 기술하면 다음과 같다.
새로 생성한 대부분의 객체는 Eden 영역에 위치한다.
Eden 영역에서 GC 가 한 번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동된다. -> Eden 영역이 가득 차야만 minor GC 가 실행된다.
Eden 영역에서 GC 가 발생하면 이미 살아남은 객체가 존재하는 Survivor 영역에 객체가 계속해서 쌓인다.
하나의 Survivor 영역이 가득 차게 되면 그 중에서 살아남은 객체를 다른 Survivor 영역으로 이동한다. 그리고 가득 찬 Survivor 영역은 아무 데이터도 없는 상태로 된다.
이 과정을 반복하다가 계속해서 살아남아 있는 객체는 Old 영역으로 이동하게 된다.
Young 영역의 동작에서 하나의 Survivor 영역은 반드시 비워져 있어야 한다. -> 만약 비워져 있지 않는다면, 비정상적인 상황으로 인지하면 된다.
HotSpot VM 에서 빠른 메모리 할당을 위해서 사용하는 두가지 기술
1. bump-the-pointer
Eden 영역에 할당된 마지막 개체를 추적한다. 마지막 객체는 Eden 영역의 맨 위에 있다. 그리고 다음에 생성되는 개체가 있으면, 해당 개체의 크기가 Eden 영역에 넣기 적당하지만 확인한다.
만약 해당 객체의 크기가 적당하다고 판정되면 Eden 영역에 넣게되고, 새로 생성된 객체가 맨 위에 있게된다.
따라서 새로운 객체를 생성할 때 마지막에 추가된 객체만 점검하면 되므로 매우 빠르게 메모리 할당이 이루어진다.
2. TLABs
bump-the-pointer 는 멀티 스레드 환경에서는 문제가 발생한다.
Thread-Safe 하기 위해서 만약 여러 스레드에서 사용하는 객체를 Eden 영역에 저장하려면 Lock 이 발생할 수 밖에 없고, lock-contention 때문에 성능은 매우 떨어지게 될 것이다.
HotSpot VM 에서 이를 해결한 것이 TLABs 이다.
각각의 스레드가 각각의 몫에 해당하는 Eden 영역의 작은 덩어리를 가질 수 있도록 하는 것이다. 각 쓰레드에서 자기가 갖고 있는 TLAB 에만 접근할 수 있기 때문에, bump-the-pointer 라는 기술을 사용하더라도 아무런 Lock 없이 메모리 할당이 가능하다.