Java

자바의 로봇청소기, 가비지 컬렉션

jimkwon 2024. 7. 9. 22:07
반응형

 

자바에는 가비지 컬렉션(Garbage Collection) 이라는 기능이 있습니다.

영문 뜻으로 짐작할 수 있듯이 사용하는 객체의 메모리를 주기적으로 검사해서 청소해주는 일을 합니다!


C와 C++같은 Unmanaged language는 free()와 같은 함수를 사용해서 직접 메모리를 해제하는 반면
Garbage Collector는 이러한 번거로운 일을 대신 해주고 있는 것이죠! (like 로봇청소기)

 

 

 

♻ 가비지 컬렉션 ( vs 가비지 컬렉터)

 

먼저, 헷갈릴 수 있는 두 용어를 정리하고 가겠습니다.

 

가비지 컬렉션

메모리 관리 프로세스로, 더 이상 사용되지 않는 메모리(객체)를 자동으로 찾아서 회수하는 작업
→ 청소

가비지 컬렉터

가비지 컬렉션을 수행하는 구성요소. 불필요한 메모리를 실제로 찾아내고 해제하는 주체
→ 청소기

 

 

♻ 가비지 컬렉션의 제거 기준

 

그렇담 가비지 컬렉션은 어떠한 기준으로 선정된 객체들을 지워버릴까요?

바로 도달성(Reachability) 이라는 개념을 통해 판단합니다.

  • Reachable : 객체가 참조되고 있는 상태
  • Unreachable : 객체가 참조되고 있지 않은 상태

객체에 유효한 참조가 없다면(Unreachable) 수거 대상으로 판단하고 지워버리게 됩니다.

 

청소좌..

 

♻ JVM 메모리에서의 객체들

 

 

Heap 영역 : 실질적으로 객체들이 생성되는 곳

이외의 Stack과 Method 영역에서는 Heap영역에서 생성된 객체의 주소를 참조하는 형식으로 구성됩니다.

보통 다음과 같은 상황에서 Heap에 있는 객체를 참조하는 변수들이 삭제됩니다.

  1. 변수의 Scope를 벗어남
    → 메소드 안에서 선언된 지역변수가 있을 때, 해당 메소드가 종료됨
  2. 참조가 다른 객체로 변경됨
    → 다른 Heap 영역의 객체를 참조하게됨
  3. 참조 변수가 null로 설정
    → 이전에 참조하면 객체에 대한 연결이 끊어짐
  4. 클래스 인스턴스의 소멸
    → 객체가 속한 클래스의 인스턴스가 소멸되면 내부의 참조변수도 같이 소멸

이러한 상황에서 2번 객체와 같이 Unreachable상태가 되며, 가비지 컬렉터의 수거 대상이 됩니다 🙂

 

 

 

 

♻ 가비지 컬렉션의 청소 과정

 

그렇다면 가비지 컬렉션은 어떠한 방식으로 청소를 하는지 좀 더 자세히 단계별로 살펴보겠습니다!

Mark And Sweep

가비지 컬렉션이 동작하는 아주 기초적인 청소과정으로, 다양한 GC에서 객체를 솎아내기 위해 사용되는 내부 알고리즘입니다.

 

  • 1. Marking (마킹)
    GC는 모든 객체를 순회하며 참조된 객체와 참조되지 않은 객체를 구분하여 마킹합니다.

 

 

  • 2. Sweep (삭제)

 

참조되지 않은 객체들(Unreachable)을 Heap에서 제거합니다.

 

  • 2-a . Compact (압축)

 

(GC 종류에 따라 해당 단계가 포함되기도, 안되기도함 😃 )

Sweep 단계를 통해 신나는 대청소 후 분산된 객체들을 Heap 시작 주소로 모아 압축합니다.

이렇게 한 데 모아두면 새로운 메모리 할당이 훨씬 쉽고 빨라지겠죠?

 

  • GC의 Root Space

https://deepu.tech/memory-management-in-programming/

Mark And Sweep(청소)를 진행하기 위해서, GC는 루트 공간을 시작으로 참조를 통해 도달할 수 있는 모든 객체들을 “살아있는“ 객체로 간주하고, 이외의 죽은(ㄷㄷ)녀석들을 청소하는 것이죠

 

 

 

 

루트 공간(Root Space)은 다음과 같습니다!

  • Stack의 로컬 변수
  • Method Area의 Static 변수
  • Native Method Stack의 JNI 참조

 

 

 

 

♻ 가비지 컬렉션의 실제 동작 과정

 

 

아래는 Runtime Data Area에 대한 그림입니다 😀
그게 무엇인고 하면 JVM이 프로그램을 수행하기 위해 OS로부터 할당받는 메모리라고 보시면 됩니다.

이 중 Heap과 Method Area는 모든 스레드가 공유하는 영역이죠!

 

https://jithub.tistory.com/40 자세한 내용은 이곳에서 🤓

가비지 컬렉션은 ‘객체의 메모리’를 주기적으로 청소합니다.

즉, 가비지 컬렉션의 대상이 되는 공간은 실제 객체가 존재하는 공간인 힙(heap)영역입니다.

그렇담 실제 힙 메모리의 구조는 어떻게 되는지 자세하게 파헤쳐 봅시다!

 

 

 

 

♻ GC의 weak generational hypothesis

 

 

 

https://docs.oracle.com/en/java/javase/16/gctuning/garbage-collector-implementation.html#GUID-23844E39-7499-400C-A579-032B68E53073

 

가비지 컬렉션의 수행(mark and sweep!)에서 매번 추적을 진행한다면, 상당한 부하가 있을겁니다!

위 그래프는 대부분의 응용 프로그램들의 object 수명을 나타낸 그래프인데요,


x축 : 측정된 object의 lifetime
y축 : lifetime이 있는 개체의 총 Byte

이 결과를 다음 사실을 알 수 있습니다!

  1. 대부분의 객체는 금방 소멸한다. (접근 불가능한 상태)
  2. 오래된 객체에서 새로운 객체로의 참조는 아주 적게 존재한다.

이를 weak generational hypothesis 이라고 합니다 🙂

 

 

힙 메모리 구조는 어디가고 이 가설을 난데없이 먼저 말하는가?

위 가설에 대한 전제를 토대로 Heap 영역이 처음 설계되었기 때문입니다.

 

 

 

 

Heap의 Young과 Old 영역

 

효율적인 메모리 관리를 위해, 객체의 생존 기간에 때라 두 가지 물리적 영역으로 나눴습니다 🙂

초기(Java7)에는 Perm 영역도 존재했지만,
Java8버전 이후에는 Native Method Stack에 편입되어 사라집니다.

 

https://aws.amazon.com/blogs/big-data/understanding-the-jvmmemorypressure-metric-changes-in-amazon-opensearch-service/

 

Young 영역(Young Generation)

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

Old 영역(Old Generation)

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

 

 

♻ Young 영역의 분리 → Eden, Survival0, Survival1

 

더더더더욱 효율적인 GC를 위해 Young 영역도 다음과 같이 세가지로 나눕니다.

Eden

  • new를 통해 새로 생성된 객체가 위치.
  • 정기적인 쓰레기 수집 후 살아남은 객체들은 Survivor 영역으로 보냄

Survivor 0 / Survivor 1

  • 최소 1번의 GC 이상 살아남은 객체가 존재하는 영역
  • Survivor 영역에는 Survivor 0 또는 Survivor 1 둘 중 하나에는 꼭 비어 있어야 하는 특별한 규칙이 있다.

 

 

Minor GC 과정 (in young Generation) 

 

 

1. 먼저, 새로운 객체가 eden 영역에 할당됩니다.

 

 

 

2. eden공간이 가득 차면 GC가 시작됩니다!

 

 

3. 마킹작업을 통해 참조된 객체들은 첫 번째 생존공간 (S0)으로 이동합니다!

이때 살아남은 녀석들의 age값이 1씩 증가합니다.

age?
객체가 Survivor 영역에서 살아남은 횟수를 의미. Object Header에 기록된다.
age값이 특정 임계값에 다다르면 Old 영역으로 이동한다.
가장 일반적인 HotSpot JVM의 의 경우는 31이다. (객체 헤더의 age 영역이 6bit임)

 

 

 

 

4. 다음 마이너 GC단계에서도 Eden이 가득차면 3번과 같이 생존공간으로 이동됩니다!
이 때, 기존 S0공간에 있던 객체중 생존 + Eden에서 생존한 객체들은 모두 S1 공간으로 이동하게 됩니다!

 

 

5. 이후 Eden 영역이 가득 차면 4번과 동일한 프로세스가 반복됩니다.
다만, 이번엔 S1이 아닌 S0 공간으로 이동하게 됩니다.

 

 

이렇듯 GC가 발생할 때마다 (Eden영역의 공간이 가득차면) 다음 일이 반복되는 프로세스를 보여줍니다 🙂

  • Eden에서 살아남은 객체가 ‘전환된 Survivor공간으로 이동되고, age가 1 증가’
  • 기존 Survivor공간에서도 살아남은 객체가 있으면 ‘전환된 Survivor공간으로 이동되고, age가 1 증가'

두 경우에 해당하면 age가 증가하고, 특정 임계치에 다다르면 드디어 Old 영역으로 이동하게 됩니다!

→ 이를 Promotion이라고 부릅니다.

 

 

♻ Major GC 과정 (in Old Generation)

 

 

 

1. 계속해서 마이너GC가 진행되면서, 끈질기게 살아남은 객체들은 점점 나이를 먹게됩니다.
만약 현재 예시의 JVM의 age임계값이 8이라고 가정하게 된다면,
Promotion이 발생하여 Old영역으로 이동합니다.

(Tenured는 Old영역과 같은 의미입니당)

 

 

 

2. 1번의 상황처럼 Promotion이 계속해서 발생할수록,
Old 영역은 계속해서 나이든 객체들이 자리를 잡게 됩니다.

 

 

 

3. 그렇게 Old영역이 다 차게된다면, 해당 공간을 정리하고 압축하는 GC 과정이 진행됩니다.
이것이 Major GC (Old 영역에서 진행되는 GC)입니다! 😎

 

 

이렇게 Minor GC와 Major GC의 동작과정을 자세하게 알아봤습니다 :)



 

 

 

 

Stop-The-World

 

앞서 Heap 구조에 대해 설명할때 언급했듯이 Young 영역은 일반적으로 Old 영역보다 크기가 작습니다.
GC가 보통 0.5초에서 1초 사이에 끝나기 때문에 Minor GC는 애플리케이션에 크게 영향을 주지 않습니다.

 

하지만 Old 영역의 Major GC는 일반적으로 Minor GC보다 시간이 오래걸리며, 10배 이상의 시간을 사용하게 됩니다.

→ 여기서 Stop-The-World 가발생!

 

 

 

 

Stop-the-World 과정


자바 가상 머신(JVM)에서 가비지 컬렉션(Garbage Collection, GC)을 수행할 때 발생하는 현상입니다.

 

Stop-the-World가 발생하면, JVM 내에서 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드가 가비지 컬렉션 작업이 완료될 때까지 멈춥니다.

 

이 과정은 가비지 컬렉터가 메모리 내의 객체들을 안전하게 검사하고, 사용되지 않는 객체를 제거하며, 필요시 메모리를 재배치(Compaction)할 수 있도록 하기 위해 필요하지요

 

다만, Major GC같은 경우 처리속도가 길기 때문에 stop-the-world 과정에서 멈춤 현상의 지속시간이 길어지고.. 애플리케이션 이용에 차질이 생기게 됩니다 😫

 

 

 

 

 

 

따라서 자바 개발진들은 Stop-the-World의 영향을 최소화하기 위해 끊임 없이 가비지 컬렉션 알고리즘을 발전 시켜왔습니다!

그 알고리즘에 대해서는.. 분량 문제로 따로 다뤄보도록 하겠습니다 🤓

 

 

 

 

 

 

Reference

 

https://www.oracle.com/webfolder/technetwork/tutorials/obe/java/gc01/index.html

 

Java Garbage Collection Basics

Java Overview Java is a programming language and computing platform first released by Sun Microsystems in 1995. It is the underlying technology that powers Java programs including utilities, games, and business applications. Java runs on more than 850 mill

www.oracle.com

 

https://inpa.tistory.com/entry/JAVA-%E2%98%95-%EA%B0%80%EB%B9%84%EC%A7%80-

%EC%BB%AC%EB%A0%89%EC%85%98GC-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%F0%9F%92%AF-%EC%B4%9D%EC%A0%95%EB%A6%AC

 

☕ 가비지 컬렉션 동작 원리 & GC 종류 💯 총정리

Garbage Collection(GC) 이란? 가비지 컬렉션(Garbage Collection, 이하 GC)은 자바의 메모리 관리 방법 중의 하나로 JVM(자바 가상 머신)의 Heap 영역에서 동적으로 할당했던 메모리 중 필요 없게 된 메모리 객

inpa.tistory.com

 

https://velog.io/@yyong3519/Garbage-Collection-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81

 

Garbage Collection 모니터링

출처

velog.io

 

special thx to chatGPT! 🤖