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

·2024년 7월 16일
0

Java

목록 보기
8/9
post-thumbnail

우선 가비지 컬렉션에 대해 얘기하기 전에, JVM에 대해 간단히 알아보고 넘어가자.

JVM(Java Virtual Machine)

자바 플랫폼의 핵심이며, 하드웨어 및 운영 체제 독립성, 컴파일된 코드의 작은 크기, 그리고 사용자 보호 기능을 제공하는 역할을 한다.

JVM은 가상 컴퓨팅 머신이다. 실제 컴퓨팅 머신처럼 명령어 세트를 가지고 있으며, 런타임에 다양한 메모리 영역을 조작한다. 자바 프로그래밍 언어에 대해 아무것도 모르며, 특정 바이너리 형식인 클래스 파일 형식에 대해서만 알고 있다. 클래스 파일에는 자바 가상 머신 명령어(또는 바이트코드)와 심볼 테이블, 기타 부가 정보가 포함한다.

쉽게 말하면, 자바 프로그램을 실행하는 가상 컴퓨터이다. 자바 코드를 기계어로 변환하고 실행한다.

이 JVM이 가비지 컬렉션을 사용하여 자동으로 메모리 관리를 해준다.

그렇다면 가비지 컬렉션은 도대체 뭘까?

가비지 컬렉션

자동 가비지 컬렉션은 힙 메모리를 검사하여 사용 중인 객체와 그렇지 않은 객체를 식별하고, 사용되지 않는 객체를 삭제하는 과정이다. 사용 중인 객체, 즉 참조된 객체는 프로그램의 일부가 여전히 해당 객체에 대한 포인터를 유지하고 있음을 의미한다. 그 반대로, 사용되지 않는 객체는 어느 부분에서도 참조하지 않으므로 객체가 사용한 메모리를 회수할 수 있다.

기본 프로세스는 다음과 같다.

  1. 마킹(Marking)
    어떤 메모리 조각이 사용 중인지, 어떤 것이 사용되지 않는지를 식별한다. 위 그림에서, 참조된 객체가 파란색이고 참조되지 않는 객체는 주황색이다. 이 단계에서 모든 객체를 스캔한다.
  2. 일반 삭제(Normal deletion)
    참조되지 않은 객체를 제거하여 참조된 객체와 포인터를 여유 공간에 남겨둔다.
    2-a. 압축을 통한 삭제(Deletion with Compacting)
    성능을 더욱 개선하려면 참조되지 않는 객체를 삭제하는 것 외에도 나머지 참조된 객체를 압축할 수도 있다.

하지만, JVM의 모든 객체를 마킹하고 압축하는 것은 비효율적이다. 더 많은 객체가 할당될수록 가비지 컬렉션 시간이 길어진다. 그렇다면 어떻게 해야 가비지 컬렉션의 효율성을 높일 수 있을까?

JVM Generations

분석에 따르면, 대부분의 객체는 수명이 짧다. 이 특성을 이용하여 힙을 더 작은 세대로 나눈다.

Young 세대(Young Generation), Old 세대(Old or Tenured Generation), 그리고 영구 세대(Permanent Generation).

Young 세대는 모든 새로운 객체가 할당되고 나이가 매겨지는 곳이다. 여기가 가득 차면 소규모 가비지 컬렉션이 발생하고, 대부분의 객체들은 생성 후 빨리 사라진다고 가정하고, 그에 맞춰 자주 빠르게 가비지 컬렉션을 한다. 일부 생존 객체는 Old 세대로 이동한다.

모든 가비지 컬렉션이 실행할 때 발생하는 현상이 있는데, 바로 stop-the-world다.

모든 애플리케이션 스레드가 작업이 완료될 때까지 중지됨을 의미하고, 메모리를 정리할 때 객체의 상태 변경을 방지하기 위함이다.

Old 세대는 오래 살아남는 객체를 저장하는 데 사용된다. Old 세대에서도 가비지 컬렉션이 발생하는데, 이를 대규모 가비지 컬렉션이라고 한다. 이때도 stop-the-world가 발생하는데, Young 세대에서 발생하는 소규모 가비지 컬렉션보다 느리다. 따라서 응답성이 중요한 애플리케이션에서는 대규모 가비지 컬렉션을 최소화해야 한다.

그럼 그림을 보면서 프로세스를 확인해보자.

  1. 객체 생성

    모든 새로운 객체는 Young 세대의 Eden 공간에 할당된다. 두 서바이버(Survivor) 공간은 비어 있다.
  2. 소규모 가비지 컬렉션
    Eden 공간이 가득 차면 발생한다. 살아있는 객체는 Survivor 공간(S0 또는 S1)으로 이동하며, 사용되지 않는 객체는 삭제된다. 소규모 가비지 컬렉션마다 객체들은 S0와 S1 사이를 이동하며, 이동할 때마다 객체의 나이가 증가한다.
    Eden과 한 Survivor 공간은 항상 비워진다(S1으로 이동하면 Eden과 S0, S0으로 이동하면 Eden과 S1이 비워진다).
  3. Promotion (승격)
    특정 나이 이상의 객체는 Old 세대로 이동하고 이를 '승격'이라고 한다.
    대규모 가비지 컬렉션은 Old 세대가 가득차면 발생한다.

이 과정이 계속 반복되며 메모리를 효율적으로 관리한다.

가비지 컬렉션에 대해 개념적으로 알아봤는데, 여러 GC 방식에 대해 더 공부해야 할 것 같다.

공식 문서와 아래 글들을 같이 보면 좋을 것 같다.

Java Garbage Collection

Java Reference와 GC

참고

Java Garbage Collection Basics

Chapter 1. Introduction

profile
개발블로그👩🏻‍💻

0개의 댓글