연구실에서 java세미나를 하던 도중 멘토가 쓰레기수집기(Garbage Collector)에 관해 제대로 알고 있는지 확인을 위해 질문을 하셨고, 얼추 대답은 했지만 좀 더 깊게 알 필요가 있다고 하셔서 자료를 찾아 공부를 해보았다.
우선 java에서는 '참조하지 않는 객체' 혹은 '유효하지 않은 메모리'를 쓰레기(=Garbage)로 분류하고, C++와 다르게 개발자가 프로그램 코드로 메모리를 명시적으로 해제하지 않기 때문에 Garbage Collector가 garbage를 찾아 지우는 작업을 한다. 다만 모든 메모리 누수를 잡아주는 것은 아님으로 메모리 누수에 대한 경계를 늦추어서는 안된다.
String[] array = new String[2];
array[0] = '1';
array[1] = '2';
array = new String[] {'G', 'C'};
위와 같이 먼저 삽입되어있던 '1'과 '2'는 새롭게 추가된 'G', 'C'로 인해 주소가 유효하지 않으므로 Garbage로 부른다.
GC를 실행시키기 위해 JVM이 애플리케이션 실행을 멈추는 것으로, stop-the-world가 실행되면 GC를 실행하는 스레드를 제외한 나머지 스레드는 모두 작업을 멈춘다. GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다. 어떤 GC 알고리즘을 사용하더라도 stop-the-world는 발생하고, 대개 GC 튜닝이란 이 stop-the-world 시간을 줄이는 것이다.
GC가 스택의 모든 변수 또는 Reachable 객체를 스캔하면서 각각 어떤 객체를 참조하는지 찾는 과정이 Mark이고, 이 과정에서 stop-the-world가 발생한다. 이후 Mark 되어있지 않는 객체들을 힙에서 제거하는 과정이 Sweep이다.
JVM을 크게 물리적 공간으로 나누면 Young 영역과 Old 영역이 있다. (Perm 영역은 잠시 배제하였다)
Young 영역에서는 주로 새롭게 생성한 객체의 대부분이 이곳에 위치한다. 대부분의 객체가 금방 접근 불가능 상태가 되기 때문에 매우 많은 객체가 이 곳에 생성되었다가 사라진다. 이 영역에서 Minor GC가 발생한다.
Old 영역에서는 접근 불가능 상태로 되지 않아 Young 영역에서 살아남은 객체가 이 곳으로 복사된다. 대부분 Young 영역보다 크게 할당하며, Young 영역보다 GC는 적게 발생한다. 이 영역에서 Major GC가 발생한다.
Young 영역은 Eden 영역과 2개의 Survive 영역으로 구성되며 Eden 영역에 최초로 객체가 만들어지고, Survivor 영역을 통해서 Old 영역으로 오래 살아남은 객체가 이동한다는 사실은 꼭 기억하기 바란다.
Old 영역의 구성에 대한 내용은 D2의 글을 참조하였다.
Reachability
java의 GC는 객체가 garbage인지 판별하기 위해 reachability라는 개념을 사용한다. 어떤 객체에 유효한 참조가 있으면 'reachable'로, 없으면 'unreachable'로 구별하고, 'unreachable' 객체를 garbage로 간주한다.
이 부분에 대해 더 알아보려면 이 글을 참고하자.