cat 2023-01-16-Java-GC.md

Java GC


2023-01-16

이전 포스팅에서 Garbage Collection에 대한 전략 세가지를 다뤘습니다. 이번 포스팅에서는 추적 전략을 사용하는 java의 Garbage Collector에 대해 다룹니다.

Java GC(Garbage Collector)

* 이 포스팅에서 다루는 java의 버전은 18입니다.

graph TD
    T[Thread] --a--> A(객체1)
    T[Thread] --b--> B(객체2)
    A(객체1) --> C(멤버)
    T[Thread] -.- D(Garbage)

이전 포스팅에서 모든 스레드에서 변수 혹은 그 변수의 멤버 등으로 참조하지 않는 객체를 garbage라고 하고 이를 찾는 것을 Garbage Collection이라 했습니다.

항상 모든 객체를 탐색하는 것은 매우 비쌉니다. java gc에서는 최적화를 위해 두가지 사실을 이용합니다.

  • 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재합니다
  • 대부분의 객체는 금방 garbage가 됩니다

즉, 젊은 객체와 오래된 객체의 판정 알고리즘을 다르게 하는 것이 유리합니다. 이를 위해 세대(Generations)를 나눠 다른 영역에 저장합니다.

  • Young 영역
    새로 생성된 대부분의 객체가 존재하는 영역
    이 영역에서의 gc를 Minor GC라고 부르며 자주 수행됩니다.
  • Old 영역
    오랫동안 생존한 객체들가 존재하는 영역
    이 영역에서의 gc를 Major GC라고 부르며 드물게 수행됩니다.

in opendjdk/src/hotspot/share/gc/serial/serialHeap.hpp

Young 영역은 Eden과 두개의 Survivor(from, to)로 구성됩니다.

사전 지식은 모두 갖췄으니, 객체가 할당되고 나서부터 관리되는 과정을 알아봅시다.

0. Entry

메모리가 할당되면, Eden 영역에서 관리됩니다.

1. Stop The World(STW)

GC가 발생할때마다, GC 스레드를 제외한 모든 스레드가 중단됩니다.(참조에 대한 race condition 방지)
GC가 종료된 후 재개됩니다.

2. Minor GC - Eden

자주 발생하는 Minor GC는 Young Gen에서

  1. 도달할 수 없는 객체를 찾아 해제합니다.
  2. 남아있는 객체를 Survivor 영역(from)으로 이동합니다.

3. Minor GC - Survivor

Survivor 영역이 가득 차면,

  1. 살아있는 객체만 골라 다른 Survivor영역(to)으로 모두 이동합니다. 이동이 이뤄지고 나면, to가 from이 됩니다.
    • 할당되었다가 해제되면 중간에 빈 공간이 생기지만, 빈 공간보다 큰 객체를 할당하는 경우 이 공간을 이용할 수 없습니다.
    • 이를 메모리 단편화라고 하며 이를 완화하기 위해 다른 Survivor로 계속 이동하면서 중간에 있는 빈 공간을 없앱니다.
  2. 특정 객체가 계속해서 살아있거나, 살아있는 객체만으로 Survivor 영역이 가득 찬 경우 오래 살아남은 객체들이 Old 영역으로 이동합니다.
    • old 영역으로 이동하는 과정을 객체가 나이를 먹는다(aging)고 표현합니다.

4. Major GC - old

드물게 발생하는 Major GC는 old 영역에서 살아 있는 객체만 남기고 해제합니다.

마치며

GC과정에서 추가로 일어나는 기법이 몇가지 있는데, 이 포스팅에서 다루진 않습니다.

  • Bump The Pointer
    빠른 할당을 위한 기법입니다.
  • TLABs
    동시성 문제를 해소하기 위해 Eden 영역을 thread local로 처리합니다.

  • 2021년 동아리 세미나에서 발표한 자료를 글로 다시 정리한 것입니다.
  • 발표 ppt는 https://fienestar.github.io/ppt/java-gc 에서 보실 수 있습니다.