[Java] 자바 가비지 컬렉션 (Garbage Collection)

손효재·2021년 11월 20일
0

Java

목록 보기
3/4

가비지 컬렉션 (Garbage Collection) 이란??

JVM 상에서 Heap 영역에 남아서 더이상 사용되지 않는 인스턴스를 가비지(Garbage)라고 한다.
GC는 Garbage가 할당된 메모리를 자동으로 해제시켜주며, 메모리 관리를 개발자가 직접 해줄 필요가 없다.

C나 C++에는 프로그래머가 수동으로 메모리 할당과 해제를 일일이 해줘야 하는 반면,
Java는 JVM에 탑재되어 있는 가비지 컬렉터가 메모리 관리를 대행해 주기 때문에,
개발자 입장에서 메모리 관리, 메모리 누수 (Memory Leak) 문제에 대해 완벽하게 관리하지 않아도 되어 개발에만 집중할 수 있게 된다.

Garbage 란??

Person person = new Person("Son");
person.hi();

person = new Person("Hyo");
person.hi();

"Son" 객체가 생성된 이후 person 변수에 의해 참조되는데, 이후 "Hyo" 객체가 생성되고 person 변수가 새로 생성된 "Hyo" 객체를 참조한다. 이때 "Son" 객체는 어떠한 경로로도 참조되지 않기 때문에 "Unreachable" 상태라고 하며, 이 객체는 가비지로 판단한다.

→ 객체의 주소값을 가지고 있는 변수가 없으면, 가비지 컬렉션은 접근할 수 없는 객체 (Garbage)라고 판단한다.

Minor GC 와 Major GC

JVM의 힙 영역(Heap Area)는 2가지를 전제로 설계된다. (Weak Generational Hypothesis)

  1. 대부분의 객체는 금방 접근 불가능한 상태가 된다.
  2. 오래된 객체에서 새로운 객체로의 참조는 아주 적게 존재한다.

즉, 객체는 대부분 일회성이며, 메모리에 오랫동안 남아있는 경우는 드물다.

Young 영역(Young Generation) - Minor GC

새롭게 생성된 객체가 할당되는 영역으로, 대부분의 객체가 금방 접근 불가능한 상태가 되므로 많은 객체가 Young 영역에서 생성되고 사라진다.

  • Eden 영역 - 새로 생성된 객체가 할당되는 영역
  • Survivor 0,1 영역 - 최소 1번의 GC 이후 살아남은 객체가 존재하는 영역
  1. 새로 생성된 객체가 Eden 영역에 할당
  2. Eden 영역이 가득 차면서 Minor GC가 발생
  • Eden 영역에서 더이상 참조되지 않는 객체의 메모리는 해제
  • Eden 영역에서 살아남은 객체는 Survivor 0,1 영역 중 하나로 이동
  1. Survivor 영역이 가득차면 살아남은 객체를 다른 Survivor 영역으로 이동
    (두 Survivor 영역 중 하나는 반드시 비어있는 상태로 남아있어야 한다.)
  2. 위 과정을 반복하다 계속해서 살아남는 객체는 Old 영역으로 이동

Old 영역(Old Generation) - Major GC

Young 영역에서 접근 가능한 상태를 유지하여 살아남은 객체가 복사되는 영역이다.
복사되는 과정에서 대부분 Young 영역보다 크게 할당되며, 크기가 큰 만큼 GC는 적게 발생한다.
Old 영역이 가득차면 Major GC가 발생하며, Minor GC 보다 시간이 오래걸린다.

GC 동작 방식

Stop-The-World

GC가 일어나면 GC를 담당하는 스레드를 제외한 모든 스레드들은 작동이 일시적으로 정지하는 것을 말한다.
따라서, 자주 일어나는 GC는 여유 메모리를 확보할 수 있지만, 성능이 저하된다.

Mark - Sweep - Compact
Mark : 사용되는 메모리를 Mark하여 사용되지 않는 메모리를 식별하는 작업이다.
Sweep : Mark 되어있지 않은 모든 오브젝트(Garbage)들을 Heap에서 제거하는 과정이다.
Compact : Sweep 후에 분산된 객체들을 Heap의 시작 주소로 모아 메모리가 할당된 부분과 그렇지 않은 부분을 압축한다.

GC 종류 및 특징

Serial GC → Parallel GC (Java 8) → Parallel Old GC → CMS GC → G1 GC (Java 11) → ZGC

Serial GC

Old 영역의 GC는 Mark-Sweep-Compact 알고리즘을 사용한다.

Old 영역에 살아있는 객체를 식별(Mark)하여 Heap 영역을 확인하여 Mark된 것만 남긴다. (Sweep)
이후 Heap 영역이 연속되게 쌓이도록 Heap의 가장 앞부분부터 채워서 객체가 존재하는 부분과 존재하지 않는 부분으로 나눈다.(Compact)

가장 간단한 GC 구현체로 싱글 스레드로 동작한다. 따라서 서버환경이나 멀티스레드에서는 좋지 않다.

Parallel GC

Serial GC와 처리하는 알고리즘이 같지만, Young 영역의 GC를 멀티 스레드로 동작한다.
따라서 Serial GC 보다 Stop-The-World가 짧다.
* Parallel Old GC는 Old 영역까지 멀티스레드로 동작한다.

GC 수행 스레드 개수, 일시중지 시간, 처리량 및 힙 크기를 지정할 수 있다.
메모리가 충분하고 코어의 개수가 많을 때 유리하며 Throughput GC라고도 부른다.

CMS (Concurrent Mark Sweep) GC

GC 동작시 Stop-The-World를 줄이기 위해 설계되었다.

  • Initial Mark - 클래스 로더에서 가장 가까운 객체 중 살아있는 객체만 Mark하여 stop-the-world가 짧다.
  • Concurrent Mark - 참조하는 객체를 따라가면서 확인한다. 이는 다른 스레드가 실행 중일때 동시에 진행
  • Remark - Concurrent Mark 단계에서 변경된 사항을 체크하여 Mark 한다. stop-the-world 발생
  • Concurrent Sweep - GC 수행, 다른 스레드가 실행중일때 동시에 진행된다.

Stop-The-World 시간이 짧아서, 어플리케이션 응답속도가 중요할 때 사용되며, Low Latency GC 라고 한다.
하지만, 다른 GC에 비해 메모리와 CPU를 더 많이 사용하고, Compaction 단계가 기본적으로 제공되지 않는다.

G1 GC

G1은 Garbage First의 약어로, Garbage만 있는 Region을 먼저 회수한다는 의미이다.
Young 영역과 Old 영영이 없이 바둑판 형식으로 메모리를 일정 부분으로 나눠서 관리한다.

Heap을 Region 이라는 일정한 부분으로 나눠서 메모리를 관리하는데,
전체 Heap에 대해서 탐색하지 않고 부분적으로 Region 단위로 탐색하여, 각각의 Region에만 GC가 발생한다.

또한, 해당 Region에 대해서만 Compaction 하면 된다.
GC의 Stop-The-World 시간이 가장 짧아서 성능이 가장 좋다.

참고

https://memostack.tistory.com/229
https://spurdev.tistory.com/10
https://coding-factory.tistory.com/829
https://hbase.tistory.com/209
https://tecoble.techcourse.co.kr/post/2021-08-30-jvm-gc/

0개의 댓글