[JAVA] 가비지 컬렉터(Garbage Collector)

henu·2024년 7월 8일

가비지 컬렉터란?


사용하지 않는 객체의 메모리를 GC(Garbage Collector)가 주기적으로 검사해서 청소해준다.

왜?

C와 C++ 같은 Unmanaged language는 free()와 같은 함수를 사용해서 직접 메모리를 해제해야한다.
Java에서는 GC가 이러한 작업을 대신 해준다.
사용하지 않는 객체의 메모리 점유는 결국 메모리 누수로 이어지게 된다.
메모리는 한정된 자원이기 때문에 사용하지 않거나 필요가 없는 부분은 해제해주는 것이 좋다.

가비지 컬렉터와 가비지 컬렉션의 차이는?


  • 가비지 컬렉터 : 메모리 관리를 담당하는 시스템 또는 프로그램의 구성 요소이며, heap을 점검하여 stack에서 더이상 참조되지 않는 객체를 찾아 제거하여 메모리를 회수하는 역할을 수행한다.
  • 가비지 컬렉션 : 메모리 관리 기술 중 하나로, 가비지 컬렉터에 의해 수행되는 프로세스를 의미

가비지 컬렉션은 프로세스 자체를 얘기하고 컬렉터는 실제 역할을 수행하는 주체를 얘기한다.

JVM Heap 메모리 영역은 어떻게 생겼을까


JVM의 한 종류인 Hotspot JVM의 Heap 영역은 이렇게 생겼다

Young, Old, Permanent Generation으로 나뉘어져 있다.

Young Generation(Young 영역)

  • 새롭게 생성된 객체가 할당(Allocation)되는 영역
  • 대부분 객체가 금방 Unreachable 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라진다.
  • Young 영역에 대한 가비지 컬렉션(Garbage Collection)을 Minor GC라고 부른다.

Old Generation(Old 영역)

  • Young 영역에서 Reachable 상태를 유지하여 살아남은 객체가 복사되는 여역
  • Young 영역보다 크게 할당되며, 영역의 크기가 큰 만큼 가비지는 적게 발생한다.
  • Old 영역에 대한 가비지 컬렉션을 Major GC 또는 Full GC라고 부른다.

Permanent Generation(Perm 영역)

  • JVM에서 클래스 메타데이터(클래스와 메소드, 필드 등의 정보)를 저장하는 곳
  • 클래스 로더는 클래스 파일을 읽어들여서 이 영역에 클래스 메타데이터를 저장한다.
  • 이 정보들은 JVM 실행 도중에 변경되지 않으며, JVM 종료 시까지 유지된다.

Perm 영역이 저장하는 정보들

  1. Class의 Meta정보
  2. Method의 Meta 정보
  3. Static Object
  4. Class와 관련된 배열 객체 Meta 정보
  5. JVM 내부적인 객체들과 최적화컴파일러(JIT)의 최적화 정보

Perm 영역은 자바 8 버전 이후 metaspace 영역으로 대체되었다고 한다.

Perm 영역은 왜 사라졌을까


위 JVM의 Heap 영역의 사진을 보면 Perm 영역이 없는데
자바 8 버전 이후에는 metaspace 영역으로 대체 되었기 때문이다.

Metaspace 영역

  • Perm 영역에서 저장하던 Class의 meta 정보들이 이 영역에 저장된다.
  • Native Memory 영역에 위치하며, JVM이 아닌 OS 레벨에서 관리된다.
  • 클래스 메타데이터와 리플렉션을 사용하는 애플리케이션에서 사용하는 일부 메모리를 저장한다.

대체된 이유

  • Perm 영역의 메모리 누수, OutOfMemoryError 등과 같은 문제
    - 클래스 로딩 및 언로딩 과정에서 메모리 할당 및 해제의 빈번한 발생으로 인해 이러한 문제가 더 심각해졌다.
  • 클래스 메타데이터를 Native Memory에 저장하면서, JVM에서의 OutOfMemoryError 문제가 해결되었다.

Reachable과 Unreachable


자바 GC는 객체가 가비지인지 판별하기 위해서 Reachability라는 개념을 사용한다.
어떤 객체에 유효한 참조가 있으면 'Reachable'로, 없으면 'Unreachable'로 구별한다.

  • Unreachable 객체를 가비지로 간주해서 GC를 수행한다.

Stop the world


GC를 실행하기 위해 JVM 애플리케이션 실행을 멈추는 것을 말한다.

  • Stop the world가 발생하면 GC를 실행하는 스레드를 제외한 나머지 스레드는 모두 작업을 멈춘다.
  • GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다.
  • GC 튜닝은 이런 stop the world 시간을 줄이는 것이다.

stop the world가 발생하는 이유

GC가 실행되는 동안에는 모든 객체의 참조 관계를 추적하고, 유효한 객체들과 그렇지 않은 객체들을 식별하여 메모리를 회수해야 하기 때문이다.
객체의 참조 관계는 실행 중에도 추적할 수 있지만, 이 작업이 매우 느리기 때문에 stop the world를 통해 일시적으로 애플리케이션을 머추고 추적 작업을 수행한다.

가비지 컬렉션 과정


  • Minor GC : Young 영역에서 수행되는 GC
  • Major GC : Old 영역에서 수행되는 GC

Minor GC

객체가 새롭게 생성되면 Young 영역 중에서도 Eden 영역에 할당(Allocation)된다.
그리고 Eden 영역이 꽉 차면 Minor GC가 발생한다.

  • 사용되지 않는 메모리는 해제되고 Eden 영역에 존재하는 객체는(사용중인) Survivor 영역으로 옮겨지게 된다.
  • Survivor 영역은 총 2개이지만 반드시 1개의 영역에만 데이터가 존재해야 한다.

Young 영역의 동작 순서

1. 새로 생성된 객체가 Edn 영역에 할당된다.
2. 객체가 계속 생성되어 Eden 영역이 꽉차게 되고 Minor GC가 실행된다.
 1) Eden 영역에서 사용되지 않는 객체의 메모리가 해제된다.
 2) Eden 영역에서 살아남은 객체는 1개의 Survivor 영역으로 이동된다.
3. 1~2번의 과정이 반복되다가 Survivor 영역이 가득 차게 되면 Survivor 영역의 살아남은 객체를 다른 Survivor 영역으로 이동시킨다. (1개의 Survivor 영역은 반드시 빈 상태가 된다.)
4. 이러한 과정을 반복하여 계속해서 살아남은 객체는 Old 영역으로 이동(Promotion)된다.

여기서 객체의 생존 횟수를 카운트하기 위해 Minor GC에서 객체가 살아남은 횟수를 의미하는 Age를 Object Header에 기록한다.

Major GC

Young 영역에서 오래 살아남은 객체는 Old 영역으로 Promotion되는 것을 확인했다.
Major GC는 객체들이 계속 Promotion 되어 Old 영역의 메모리가 부족해지면 발생하게 된다.

Old 영역에 대한 GC

  • Serial GC
  • Parallel GC
  • Parallel Old GC(Parallel Compacting GC)
  • Concurrent Mark & Sweep GC(CMS)
  • G1(Garbage First) GC

마크 앤 스윕(Mark and Sweep)


Mark는 표시하다 Sweep은 쓸어내리다, 소멸의 뜻을 가지고 있다.

GC Root는 실행중인 스레드, 정적 변수, 로컬 변수, JNI 래퍼런스와 같은 것들이 될 수 있다.

GC는 객체에 Mark를 하고 Mark가 되지 않은 객체의 메모리를 해제하게 된다.
Mark가 안된 객체는 Unreachable 객체이다.

마크-스윕-컴팩트(mark-sweep-compact)


Old 영역에는 대부분 큰 객체들이 저장되는데 Mark and Sweep 알고리즘을 사용하면 큰 객체들을 처리할 때 많은 시간과 메모리가 소비된다고 한다.
대신 Old 영역에서는 mark-sweep-compact 알고리즘이 사용된다.

  • 객체를 메모리에서 삭제하는 대신 객체들을 메모리의 한쪽으로 몰아서 공간을 최적화하는 "compact"작업을 수행한다.
  • 이를 통해 메모리 단편화를 최소화하고 성능을 향상 시킬 수 있다.

profile
주니어 백엔드 개발자입니다

0개의 댓글