Garbage Collection(가비지 컬렉션)
가비지 컬렉션이란 메모리 관리 기법중에 하나로 JVM의 Heap 영역에서 동적으로 할당했던
메모리 중 필요없게 된 메모리 객체를 모아 주기적으로 제거하는 프로세스를 뜻합니다.
다른 언어 같은 경우는 프로그래머가 수동으로 메모리 할당 및 해제를 해줘야 했지만 Java에선 가비지 컬렉터가 메모리 관리를
대신해주기 때문에 개발자 입장에서 메모리 누수 문제에 대해 관리하지 않고 개발에만 오롯이 집중할 수 있는 장점이 있습니다.
참고로 가비지 컬렉터 개념은 자바에만 있는 개념은 아닙니다. 파이썬, 자바스크립트 및 브라우저 역시 자체적인 가비지 컬렉션이
구현되어 있기 때문에, 메모리 관리 없이 웹페이지를 만들 수 있습니다.
가비지 컬렉션 대상
가비지 컬렉션은 어떤 객체를 가비지로 판단하고 지워버리는 걸까요? 이를 위해 특정 객체의 도달 능력(ReachAbility)을
기준으로 판단하게 됩니다. 도달 능력을 간단히 말하면, 객체의 레퍼런스가 있으면 (Reachable) 이고,
객체의 유효한 레퍼런스가 없으면 (Unreachable)이 되게 됩니다.
가비지 컬렉션은 도달 능력이 없는 Unreachable 객체를 가비지 컬렉션은 수거하게 됩니다.
public class Main {
public static void main(String[] args) {
Obj a = new Obj();
System.out.println(a);
a = new Obj();
System.out.println(a);
}
}
위와 같은 경우, a라는 참조변수는 new Obj()라는 객체를 레퍼런스로 참조하고 있습니다. 하지만 이후 새로운
객체 new obj()를 할당받게 됩니다. 그럼 이전에 선언했던 Obj는 더 이상 해당 객체를 참조하는 레퍼런스가 없어져
Unreachable 상태가 되어 가비지 컬렉션에 의해 처리가 되게 됩니다.

자바에서 객체들은 메모리의 Heap 영역에 저장됩니다. 반면에 참조변수나 지역 변수들은 Method 영역 또는
Stack 영역에 저장됩니다. 위의 예제 에서 new Obj()는 새로운 객체를 뜻합니다. 당연히 힙영역에 저장되게 되죠
하지만 Obj a 는 참조변수에 속하기 때문에 Stack 영역에 저장되게 됩니다. 둘 사이는 연결된 상태입니다. 하지만
참조변수 a에 새로운 객체가 할당되면 기존의 객체의 연결이 끊기기 때문에 이러한 객체들은 가비지 컬렉터가 제거해주게 됩니다.
가비지 컬렉션 청소 방식
가비지 컬렉터는 Unreacable 객체를 어떤 방식으로 제거할까요?
- Mark and Sweep

- Mark
먼저 가비지 컬렉션의 대상이 될 객체를 식별합니다. Root Space에서 부터 시작하여 그래프 순회를 통하여
연결된 객체들을 찾아내 어떤 객체를 참조하고 있는지 찾아서 파악하는 것이죠. 해당 과정은 Mark라고 합니다.
- Sweep
두 번째로 참조하고 있지 않은 객체들을 Heap에서 제거합니다. 해당 과정을 Sweep이라고 합니다
- Compact
마지막으로 Sweep후에 분산되어 있는 객체들을 Heap의 시작주소로 모아 메모리가 할당된 부분과 그렇지 않은 부분으로 압축합니다.
가비지 컬렉션 동작 방식
힙 영역은 가비지 컬렉션의 대상이 되는 공간입니다. 힙 영역은 애초에 설계할 때 다음과 같은 전제로 설계되었습니다.
1. 대부분의 객체는 금방 접근 불가(Unreachable)상태가 된다.
2. 오래된 객체에서 새로운 객체로의 참조 경우는 매우 적다.
이를 다시 말하면, 객체는 대부분 일회성이며 메모리에 오래 남아있는 경우는 적다는 의미가 됩니다. JVM 개발자들은 이러한 특성을 이용해 메모리를 객체의 생존기간에 따라 Young과 Old 영역으로나누었습니다.

Young영역 (Young Generation)
- 새롭게 생성된 객체가 할당되는 지역
- 대부분의 객체가 금방 Young 영역에 생성되었다가 사라진다.
- Young 영역에 대한 가비지 컬렉션을 Minor GC라고 부릅니다.
Old영역 (Old Generation)
- young 영역에서 Reachable 상태를 유지하여 살아남은 객체가 복사되는 영역입니다.
- young 영역보다 크게 할당됩니다.
- Old 영역에 대한 가비지 컬렉션은 Major GC 혹은 Full GC라고 부릅니다.
여기서 끝이 아니라 효율적인 GC를 위해 Youg 영역을 3가지 영역으로 다시 나누게 됩니다.

Eden
- new를 통해 새로 생던된 객체가 위치하는 곳입니다.
- Minor GC 이후 살아남은 객체들은 Survivor 영역으로 보냅니다.
Survivor0과 Survivor1
- 최소 1번 GC 이상 살아남은 객체가 존재하는 영역입니다.
- 둘중에 한 영역은 꼭 비어있어야 합니다.
Minor GC의 과정
Young Generation 영역은 짧게 살아남은 메모리들이 존재하는 공간입니다. 모든 객체는
처음에 Young Generation에 생성되게 됩니다. 위에서 봤다 싶이, Old에 비해 Young 공간은
상대적으로 작기 때문에 메모리 상의 객체를 찾아 제거하는데 적은 시간이 소요됩니다.
따라서 Young 영역에서 발생하는 GC를 Minor GC라고 부릅니다.
동작 과정은 다음과 같습니다.
1. 처음 생성된 객체는 Young 영역의 일부인 Eden에 위치합니다.

2. 객체가 계속 생성되면 Eden 영역이 꽉차게 되고 Minor GC가 실행됩니다.

3. Mark를 통해 reachable 객체를 탐색합니다.

4. Eden 영역에서 살아남은 객체는 1개의 Survivor 영역으로 이동합니다. 나머지 Unreachable 객체들은
sweep(메모리 해제)를 합니다.

5. 살아남은 모든 객체들의 age 값이 1씩 증가하게 됩니다. 여기서 age값은 살아남은 횟수를 뜻합니다.
이 값이 임계값이 다다르면 Young 영역에서 Old 영역으로 이동합니다. 객체 헤더에 age를 기록하는 부분이 6비트로
되어 있기 때문에 기본 임계값은 31이됩니다.

Major GC의 과정
Old Generation은 길게 살아남은 메모리들이 존재하는 영역입니다. Old 영역에 객체가 가득차게 되어 메모리가 부족해지면 Major GC가 일어나게 됩니다.
Minor GC는 Young 메모리 대상으로 실행되고 Eden 영역이 가득 찰 경우 실행되게 됩니다. 또한 상대적으로 실행속도가 빠른 특징이 있습니다. 이에 반면에 Major GC는 Old 메모리를 대상으로 하고 Old 영역이 가득 찰 경우 실행되게 됩니다.
또한 Minor GC에 비해 Major GC는 실행속도가 느린 특징을 지닙니다.
이전에 Old 영역은 Young 영역에 비해 상대적으로 큰 공간을 지니고 있다 했습니다. 따라서 객체 제거에 많은 시간을
소요하게 됩니다. Minor GC의 경우 0.5 ~ 1초 사이에 작업이 끝나지만 Major GC는 그 10배의 시간이 소요됩니다.
여기서 Stop the Wrold 문제가 발생하게 되는데, 실행되고 있던 모든 쓰레드들이 중지되고 Major GC를 위한 Mark and Sweep 작업 때문에 CPU에 부하를 주게 됩니다. 이를 해결하기 위해 다양한 알고리즘들이 만들어 졌습니다. 이에 대해서는 다음 글을 통해
다뤄보도록 하겠습니다.
감사합니다!
참고 블로그
'Java' 카테고리의 다른 글
제너릭이란? (1) | 2023.04.12 |
---|---|
추상클래스와 인터페이스 (2) | 2023.04.09 |
자바 변수를 메모리 관점에서 뜯어보기 (0) | 2023.04.01 |
객체지향 프로그래밍이란? (0) | 2023.03.13 |
Java - ArrayList와 LinkedList (0) | 2022.01.18 |