이전에 GC 를 학습하면서 간단히 정리했던 내용

1. Garbage Collector ??

Garbage Collector 는 JVM 의 구성 요소 중 하나로 참조하고 있지 않는 객체를 메모리로 반환하는 역할을 하는 컴포넌트이다. 즉, 사용하지 않는 객체를 찾아 지우는 역할을 한다. Java 의 패러다임 중 하나인 "메모리를 자동으로 할당하고 할당 해제하므로 프로그램이 해당 작업에 부담을 느끼지 않는다." 는 취지에서 Garbage Collector 가 도입되었다. 

(3) Automatic Garbage Collection - Java automatically allocates and deallocates memory so programs are not burdened with that task.

 

 

2. 가비지 컬렉션 과정 - Generational Garbage Collection 

GC 를 실행하기 위해서는 JVM 이 애플리케이션이 실행을 멈추고 메모리를 회수해야 한다. 이 과정을 한마디로 stop-the-world 라 말한다. 다른 말로는 GC 가 실행되는 동안에는 애플리케이션이멈춰 있어야 한다. 만약 애플리케이션이 오랫동안 멈춰있다면 서비스를 제공할 수 없고 사용자에게 나쁜 경험을 제공할 수 있기 때문에 GC 튜닝을 통해 stop-the-world 시간을 줄여야 한다.

 

GC 은 대부분의 객체는 금방 참조되지 않는 상태가 되며, 오래된 객체의 젊은 객체 참조는 적게 존재한다는 가설을 기반하며 HotSpot VM 은 Young Generation 와 Old Generation 로 공간을 나누어 관리한다.

  • Young Generation : 새롭게 생성된 객체가 위치하는 영역이며 대부분 금방 참조되지 않는 상태가 되기 때문에 해당 영역에서 생성되었다가 사라진다. 이 영역에서 객체가 사라지는 과정을 Minor GC 라 부른다.
  • Old Generation : YoungGeneration 에서 살아남은 객체가 복사되는 영역이다. YoungGeneration 보다 큰 크기로 할당되며, 큰 크기 만큼 GC 가 적게 발생한다. 이 영역에서 객체가 사라지는 과정을 Full GC 라 부른다.

 

GC 영역 및 데이터 흐름도 (source : Naver D2)

 

3.  Young Generation 구성

Young Generation 은 객체가 제일 먼저 생성되는 구간이다. Young Generation 은 Eden 영역과 2개의 Survivor 영역으로 총 3개의 영역으로 구성되어 있다.  각 영역의 처리 순서는 아래와 같다.

 

  1. 새로 생성된 객체는 Eden 영역에 위치한다. Eden 영역에서 Minor GC 가 발생하고 살아남은 객체는 Survivor 영역으로 이동한다.
  2. Eden 영역에서 Minor GC 가 발생할 때마다 살아남은 객체는 Survivor 영역으로 이동하며 가득 차게 될 경우, 다른 Survivor 영역으로 옮겨진다. (하나의 Survivor 영역은 빈 공간으로 사용된다.)
  3. 해당 과정이 반복되고 그 중 살아남은 객체는 Old 영역으로 이동한다.

4. Card Table

Old Generation 가 Young Generation 객체를 참조하는 경우를 처리하기 위해 사용되는 512바이트 청크이다. 카드 테이블에 Old Generation 의 객체가 Young Generation 의 객체를 참조할 때마다 정보가 표시되며 Young Generation 의 GC 를 실행할 때, Card Table 의 Old Generation 의 객체를 탐색해 전체 Old Area 를 탐색하지 않는 장점이 있다.

card table structure (source : Naver D2)

 

 

5. Major GC 의 대표적 동작 방식 : mark-and-sweep-compaction

 대체적으로 GC 는 사용하지 않는 객체를 식별하고, 식별한 객체를 제거하는 과정을 거친다. 대표적인 알고리즘으로 Old GC 의 mark-and-sweep-compact algorithm 이다. mark-and-sweep-compact algorithm 은 크게 3가지 과정을 거쳐 동작한다.

  1. marking : GC 가 사용되지 않는 메모리를 식별하는 단계
  2. deletion with compacting : 참조되지 않은 객체를 제거하여 참조 객체를 압축하여 성능을 향상시키는 단계

 

 

Step 1: Marking

step01. marking

 GC 가 사용되지 않는 메모리를 식별하는 단계이다. Java GC 는 유효한 참조된 객체를 유효하다고 판별한다. 이 때 가장 최초의 참조를 root set 이라 정의하며, root set 의 기준은 아래와 같다. 

  • Java 메서드 실행 시에 사용하는 지역 변수파라미터들에 의한 참조 (Java 스택)
  • JNI(Java Native Interface)에 의해 생성된 객체에 대한 참조 (네이티브 스택)
  • 메서드 영역의 정적 변수에 의한 참조

rumtime data area (Oracle HotSpot VM)

 

 

Step 2 : deletion with compacting

step2. normal deletion

 

참조되지 않은 객체를 제거하여 참조된 객체와 포인터를 여유 공간에 남기고 압축 과정을 통해 성능을 향상하는 과정을 말한다.

 

 

6. Major GC 에는 다양한 방식이 있다.

방금 언급했던 mark-and-sweep-compact algorithm 알고리즘을 사용하는 Major GC 는 Serial GC, Parallel GC 이다. 다른 GC 또한 이 알고리즘을 활용한 GC 도 존재하고 Java11 의 default Major GC 인 G1 GC 와 같이 다른 컨셉의 알고리즘으로 동작하는 Major GC 가 존재한다. 이 부분은 깊게 파면 끝이 없기 때문에 모든 것을 알려고 하기 보다는 컨셉을 비교하고 필요한 내용들을 하나씩 알아가보는 식으로 학습하려고 한다. 

 

 

Reference