8 Jul 2020
java GC
Java Garbage Collection
가비지 컬렉션 과정
GC를 알아보기전 ‘stop the world’라는 용어를 알아야한다
‘stop the world’란 GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것이다
‘stop the world’가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다
GC작업을 완료한 이후 중단했던 작업을 다시 시작한다. 어떤 GC알고리즘을 사용하더라도
‘stop the world’는 발생한다. 대개의 경우 GC튜닝이란 이 ‘stop the world’ 시간을 줄이는 것이다.
Java에서는 개발자가 메모리를 명시적으로 해제하지 않기 때문에 GC가 필요없는 객체를 찾아
지우는 작업을 한다. GC는 다음의 두가지 전제하에 만들어졌다.
-
대부분의 객체는 금방 접근 불가능이 된다.
-
오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
가비지 컬렉션의 기본은 유효한 참조가 없는 객체가 점유하고 있던 메모리를 가상머신으로 돌려주는 것이다.
이러한 전제 조건에 따라 크게 2개의 물리적 공간을 나누었는데 ‘young’ 영역과 ‘old’영역
이다.
-
Young영역 : 새롭게 생성한 객체의 대부분이 여기에 위치한다. 대부분의 객체가 금방 접근
불가능 상태가 되기 때문에 많은 객체가 Young영역에 생성되었다가 사라진다. 이 영역에서
객체가 사라질때 Minor GC가 발생한다고 말한다.
-
Old영역 : 접근 불가능 상태로 되지 않아 Young영역에서 살아남은 객체가 여기로 복사된다.
대부분 Young영역보다 크게 할당하며, 크기가 큰 만큼 Young영역보다 GC는 적게 발생한다.
이 영역 에서 객체가 사라질때 Full GC가 발생한다고 말한다.

위 그림의 Permanent Genernation 영역 은 Method area라고도 한다. 객체나 문자열정보를
저장하는 곳이며 Old영역에서 살아남은 객체가 영원히 남아 있는 곳은 아니다. 이 영역에서
GC가 발생할 수도 있는데 여기서 발생해도 Full GC의 횟수에 포함된다.
Young 영역의 구성
Young 영역은 3개의 영역으로 나뉜다.
각 영역의 처리 절차 순서
-
새로 생성한 대부분의 객체는 Eden영역에 위치한다.
-
Eden 영역에서 GC가 한 번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동된다.
-
Eden 영역에서 GC가 발생하면 이미 살아남은 객체가 존재하는 Survivor 영역으로 객체가 계속 쌓인다.
-
하나의 Survivor 영역이 가득 차게 되면 그 중에서 살아남은 객체를 다른 Survivor 영역
으로 이동한다. 그리고 가득찬 Survivor 영역은 아무 데이터도 없는 상태로 된다.
-
이 과정을 반복하다가 계속해서 살아남아 있는 객체는 Old영역으로 이동하게 된다.
이 절차에서 Survivor 영역 중 하나는 반드시 비어 있는 상태로 남아 있어야 한다.
만약 두 Survivor 영역에 모두 데이터가 존재하거나, 두 영역 모두 사용량이 0이라면 시스템
이 정상적인 상황이 아닌 것이다.
이 절차를 그림으로 보면 다음과 같다.

핵심 Point : Eden 영역에서 최초로 객체가 만들어지고, Survivor영역을 통해서
Old영역으로 오래 살아남은 객체가 이동한다는 사실은 꼭 기억하자
Old 영역에 대한 GC
Old 영역은 기본적으로 데이터가 가득 차면 GC를 실행한다. GC방식은 JDK7을 기준으로
5가지 방식이 있다.
-
Serial GC
-
Parallel GC
-
Parallel Old GC(Parallel Compacting GC)
-
Concurrent Mark & Sweep GC(이하 CMS)
-
G1(Garbage First) GC
이 중에서 Serial GC는 운영서버에서 절대 사용하면 안된다. CPU코어가 하나만 있을 때
사용하기 위해서 만든 방식이기 때문에 사용시 애플리케이션 성능이 많이 떨어진다.
Serial GC
young에서는 앞서 말한 방식을 사용, old영역에서는 Mark-sweep-compact 콜렉션 알고리즘을
따릅니다. 이 알고리즘에 대해서 간단하게 말하면, 안 쓰는 거 표시해서 삭제하고 한 곳으로
모으는 알고리즘입니다.
*Mark-sweep-compact
-
Old 영역으로 이동된 객체들 중 살아 있는 개체를 식별합니다. (Mark)
-
Old 영역의 객체들을 훑는 작업을 수행하여 쓰레기 객체를 식별합니다. (Sweep)
-
필요 없는 객체들을 지우고 살아 있는 객체들을 한 곳으로 모은다 (Compact)
Parallel GC
Serial과는 달리 Young영역에서의 콜랙션을 병렬로 처리한다. 다수의 cpu를 사용하기 때문에
GC의 부하를 줄이고 애플리케이션의 처리량을 늘릴 수 있다.
마찬가지로 Mark-sweep-compact 알고리즘을 사용한다.
Parallel Old GC
Young영역에 대한 GC는 병렬 콜렉터와 동일 하지만 old에서는 다음 3단계를 거친다.
*Mark-sweep-compact
-
Old 영역으로 이동된 객체들 중 살아 있는 개체를 식별합니다. (Mark)
-
Old 영역의 객체들을 훑는 작업을 수행하여 쓰레기 객체를 식별합니다. (Sweep)
-
필요 없는 객체들을 지우고 살아 있는 객체들을 한 곳으로 모은다 (Compact)
병렬 콜렉터와 동일하게 여러 cpu를 사용하는 서버에 적합하다.
CMS 콜렉터
초기 Initial Mark 단계에서는 클래스 로더에서 가장 가까운 객체 중 살아 있는 객체만 찾는 것으로 끝낸다. 따라서, 멈추는 시간은 매우 짧다. 그리고 Concurrent Mark 단계에서는 방금 살아있다고 확인한 객체에서 참조하고 있는 객체들을 따라가면서 확인한다. 이 단계의 특징은 다른 스레드가 실행 중인 상태에서 동시에 진행된다는 것이다.
이러한 단계로 진행되는 GC 방식이기 때문에 stop-the-world 시간이 매우 짧다. 모든 애플리케이션의 응답 속도가 매우 중요할 때 CMS GC를 사용하며, Low Latency GC라고도 부른다.
단점은 다음과 같다.
다른 GC 방식보다 메모리와 CPU를 더 많이 사용한다. Compaction 단계가 기본적으로 제공되지 않는다.
따라서, CMS GC를 사용할 때에는 신중히 검토한 후에 사용해야 한다. 그리고 조각난 메모리가 많아 Compaction 작업을 실행하면 다른 GC 방식의 stop-the-world 시간보다 stop-the-world 시간이 더 길기 때문에 Compaction 작업이 얼마나 자주, 오랫동안 수행되는지 확인해야 한다.
G1 GC
참고