본문 바로가기

Java/JVM

Garbage Collection이란

 

GC(Garbage Collection)

 

 

Java 의 메모리 관리기법중 하나로 Heap 영역(동적으로 할당한 메모리 객체)에서 사용하지 않는 객체를 주기적으로 제거하는 기능입니다. 

(내부적으로 finalize() 메서드를 호출하여 객체를 메모리에서 해제시킨다고 합니다)

 

하지만 GC에도 명확한 단점이 존재하는데 이는 아래에서 다루겠습니다.

 

 

 

 

그렇다면 어떻게 사용하는 객체와 사용하지 않는 객체로 구분하나요?

 

 

Java GC는 객체가 쓰이는지 판별하기 위해서 reachability라는 개념을 사용합니다.

참조가 있으면 'reachable' 없으면 'unreachable'로 구별하고, 여기서 'unreachable' 상태를 가비지로 간주해 GC를 수행합니다.

 

Heap영역에 있는 객체들에 대한 참조는 다음 4가지 종류 중 하나입니다.

  • 힙 내의 다른 객체에 의한 참조
  • Java 스택 (메서드 실행 시에 사용하는 지역 변수와 파라미터들) 에 의한 참조
  • 네이티브 스택, 즉 JNI(Java Native Interface)에 의해 생성된 객체에 대한 참조
  • 메서드 영역의 정적 변수에 의한 참조

https://d2.naver.com/helloworld/329631

 

위 사진과 같이 Root Set(시작점) 으로 시작해서 참조가 일어나는 파란색 객체는 reachable, 빨간색 사슬의 객체와 같이 참조관계가 없다면 unreachable 객체로 판별합니다.

 
 
 
사용하는 객체를 판별하는 방법은 알겠고, GC가 동작하는 방식은 어떻게 되나요?

 

 

Mark and Sweep 알고리즘은 가장 많이 사용되는 GC의 제거 방식으로 알고리즘의 이름 그대로 마킹해제(제거) 하는 방식입니다

 

1. Mark : Root부터 시작하여 그래프 순회를 하며 메모리 영역에 1bit씩 남겨 사용 중 표시를 마킹합니다

2. Sweep : Mark 과정에서 마킹이 되지 않은 객체들(참조하지 않는 객체들)을 힙 영역에서 제거합니다

(JVM 메모리 모델에 따라 Sweep 될수도, 옮겨질수도 있다고 합니다)

3. Compact : Sweep이 일어난 후 살아남은 객체들을 빈 공간 없이 연속적으로 붙여주는 압축 작업입니다.

(Compact 단계가 있으면 Mark - Sweep - Compact 알고리즘 이라고 합니다)

 

 

 

 

그러면 어떤 상황에서 GC가 발생하나요? 

 

 

GC의 발생과정을 보기위해 Heap의 구조부터 간단히 살펴보자면

https://www.javamadesoeasy.com/2016/10/jvm-heap-memory-hotspot-heap-structure.html

 

JVM 메모리의 힙 영역은 크게 Young(New)-Generation /  Old-Generation 구성되어 있습니다.
Young-Generation 은 새롭게 생성된 객체가 들어오는 곳으로, 위 사진에서 처럼 eden / Survivor0 / Survivor1로 나눠집니다
  • eden은 new를 통하여 새롭게 생성된 객체가 위치하는 곳이고
  • servivor은 한번이상 살아남은 객체들이 존재하는 곳입니다
Old-Generation은 위 사진에서 보이듯 Young-Generation 보다 크게 할당됩니다. 왜냐하면 대부분의 객체는 Young영역에서 참조되지 않는 상태가 되어 금방 제거(Sweep)되기 때문입니다.

 

 

 
Garbage Collection Process

새롭게 생성된 객체가 Young-Generation의 Eden영역에 들어왔습니다.

 

 

Eden영역이 새로운 객체들로 차게되고, 더이상 공간이 없어지면 GC가 일어납니다.

* 이 때 발생하는 GC를 MinorGC라고 합니다

 

 

MinorGC가 일어나는 시점에 사용하지않는 객체들은 Sweep(제거)되고,

아직 사용하고있는(Referenced) 객체들은 S0으로 이동됩니다. 

 

이렇게 살아남은 객체는 age를 기록하게 됩니다.

(일반적인 JVM 값의 age 영역은 6bit 입니다. 따라서 임곗값은 31이 됩니다)

 

 

새로운 객체들로 인해 공간이 없어진 Eden영역엔 또다시 MinorGC가 일어납니다.

 

Eden에 존재하는 객체들은 S1 로 이동합니다

(물론 사용하지 않는 객체들은 Sweep됩니다)

 

S0에 존재하는 객체들도 S1로 이동합니다.

이 객체들은 age값이 2가됩니다.

(여기서도 참조되지 않는 객체들은 Sweep됩니다)

 

*Servivor0 과 Servivor1 중 한 영역은 반드시 비어있어야 합니다

 

allocation - copying 과정을 반복하보면 age가 점점 차게되고
age가 임계값이 된 객체들은 진급(promotion)과정을 거치며 Old-Generation으로 이동합니다.
(위 예제에서의 임계값은 8이네요.)

진급 과정을 계속 거치다 보면 결국 Old-Generation도 꽉 차게되는데

* 이때 일어나는 GC를 MagorGC(FullGC)라고 부릅니다

GC의 단점

GC작업을 하고있는 동안 GC스레드를 제외한 모든 스레드는 정지하게 되는데 이 문제를STW(Stop the world)라고 합니다.

MajorGC
는 Old-Generation 에서의 모든 객체를 조사하여 GC를 발생시킵니다.

따라서 Young-Generation 보다 약 10배의 소요시간을 가지며, Young-Generation 보다 긴 STW가 발생하게 됩니다.

 

 

 


 

 

정리해보면?

 

 

GC의 원리에 대해 알아보았고 다양한 알고리즘의 GC가 있는데 이는 후에 정리해보겠습니다.

 

  • GC는 동적으로 할당된 사용하지않는(unreachable)객체를 Heap에서 주기적으로 지워주는 기능입니다.
  • 객체가 사용하고있는지 아닌지는 참조를 통해 판별합니다.
  • GC는 대표적으로 Mark-and-Sweep 알고리즘을 사용하여 사용하지 않는 객체를 제거합니다.

  • GC는 발생하는 영역에따라 MinorGC와 Major(Full)GC로 분류합니다.
  • MinorGC는 Young-Generation에서 참조가 일어나지 않는(사용되지 않는)메모리 상의 객체를 제거합니다.
  • MajorGC는 Old-Generation에서 발생하며, Old-Generation안의 모든 객체를 조사하여 GC를 발생시키므로 많은 오버헤드를 발생시킵니다.

 

 


 

 

출처

https://d2.naver.com/helloworld/329631 

 

https://siahn95.tistory.com/108?category=866017 

 

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

 

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#heap_%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%9D%98_%EA%B5%AC%EC%A1%B0