Garbage Collection(가비지 컬렉션)

Java 프로그래밍 언어는 메모리 관리를 자동화하기 위해 가비지 컬렉션(Garbage Collection, GC)이라는 메커니즘을 사용한다. 개발자가 명시적으로 메모리를 해제하지 않아도 더 이상 사용되지 않는 객체를 자동으로 식별하고 회수하는 프로세스이다.

개념

프로그램을 개발하다 보면 더 이상 사용하지 않는 유효하지 않은 메모리인 가비지(Garbage)가 발생하게 된다. C언어에서는 free() 함수를 통해 직접 명시적으로 해제했지만, Java에서는 가비지 컬렉터가 자동으로 메모리를 회수한다.

Book book = new Book();

// book 객체 사용

book = null; // 위에서 생성된 Book은 더 이상 참조하지 않게 됨

위 코드에서 객체는 null로 설정된 후 더 이상 참조되지 않아 필요 없는 객체가 되기 때문에, 가비지 컬렉터에서 이를 감지하고 메모리를 회수하게 된다.

전제

JVM의 Heap 영역은 다음 두 가지 전제를 기반으로 설계되었다.

  • 대부분의 객체는 금방 접근 불가능한 상태(Unreachable)가 된다.

  • 오래된 객체에서 새로운 객체로의 참조는 드물게 발생한다.

즉, 객체는 대부분 일회성이며, 메모리에 오랫동안 남아있는 경우는 드물다는 것을 기반으로 설계되었다.

영역 구분

위 전제를 기반으로 했기 때문에 JVM의 Heap 영역은 객체의 생존 기간에 따라 Young Generation과 Old Generation으로 나누어진다.

  • Young Generation

    • 새로 생성된 객체가 할당되는 영역

    • 대부분의 객체는 금방 사라지기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라짐

    • Young 영역에 대한 가비지 컬렉션을 Minor GC라고 부름

    • 더 효율적인 GC를 위해 Young 영역을 세 부분으로 나눔

      • Eden: 새로 생성된 객체가 할당되는 영역

      • Survivor: Eden 영역에서 살아남은 객체가 복사되는 영역, 두 개의 Survivor 영역이 존재

        • 두 영역 중 하나는 항상 비어있으며, 한 번에 하나의 Survivor 영역만 사용

  • Old Generation

    • Young 영역에서 살아남은 객체가 복사되는 영역

    • 크기가 큰 객체는 바로 Old 영역에 할당됨

    • Young 영역보다 크게 할당되며, 가비지는 적게 발생

    • Old 영역에 대한 가비지 컬렉션을 Major GC라고 부름

Card Table

종종 Old 영역에 있는 객체가 Young 영역의 객체를 참조하는 경우가 발생할 수 있는데, 이를 위해 Old 영역에는 카드 테이블이 존재한다. 카드테이블이 없으면, Minor GC가 실행될 때 Old 영역의 객체가 Young 영역의 객체를 참조하는지 확인하기 위해 모든 객체를 스캔해야 하므로 성능 저하의 원인이 된다.

  • 카드 테이블은 Old 영역에 있는 객체가 Young 영역의 객체를 참조할 때마다 그 정보를 표시

  • Young 영역에서 가비지 컬렉션이 진행될 때 카드 테이블만 조회하여 GC의 대상인지 식별할 수 있도록 함

GC 동작 방식

가비지 컬렉션이 실행된다고 했을 때 기본적으로 Stop-the-world가 발생하게 된다.

  • 가비지 컬렉션을 실행하기 위해 JVM이 애플리케이션의 실행을 멈추는 것

  • GC가 실행될 때는 GC를 실행하는 쓰레드를 제외한 모든 쓰레드들의 작업 중단(GC가 완료되면 작업 재개)

때문에 Stop-the-world의 시간을 줄이는 것이 GC 성능 개선의 핵심이 된다.

Minor GC

Minor GC는 작은 영역에서 최적화된 가비지 컬렉션을 수행하므로, 실행 시간이 짧기 때문에 애플리케이션에 큰 영향을 주지 않는다. Minor GC는 다음과 같은 과정을 거치게 된다.

  1. 새로 생성된 객체가 Eden 영역에 할당

  2. Eden 영역이 꽉 차면 Minor GC가 실행

    1. Eden 영역에서 사용되지 않는 객체의 메모리 해제

    2. Eden 영역에서 살아남은 객체는 Survivor 영역으로 이동

  3. 2번 과정이 반복되다가 하나의 Survivor 영역이 가득 차면 살아남은 객체를 다른 Survivor 영역으로 이동

  4. 계속해서 살아남은 객체는 Old 영역으로 이동

3번 과정에서 하나의 Survivor 영역은 반드시 빈 상태가 되면서, 두 영역을 번갈아가며 사용하게 되는데, 그 이유는 성능과 관련이 있다.

  • Survivor 영역의 메모리를 정리하면 메모리들은 연속적으로 배치되지 않게 되면서 단편화 발생

  • 새 영역으로 이동하게 되면 메모리가 연속적으로 배치됨

결과적으로 메모리 단편화가 줄어들어 가비지 컬렉션 성능을 향상시킬 수 있게 된다.

Major GC

Young 영역에서 오래 살아남은 객체는 Old 영역으로 이동하게 되는데, Major GC는 객체들이 계속 Promotion되어 Old 영역의 메모리가 부족해지면 실행된다. Young 영역보다 Old 영역이 크기 때문에 Major GC는 Minor GC보다 더 오랜 시간이 소요되기 때문에 애플리케이션에 더 큰 영향을 주게 된다.

참고자료

Last updated