본문 바로가기
Programming/JAVA

[Java] JVM GC 기본 동작 방식 이해하기

by 코딩의성지 2021. 8. 4.

예전에 내가 JVM 메모리가 어떻게 관리되는지 포스팅을 했었다.

 

https://devkingdom.tistory.com/226

 

[JAVA] JAVA 메모리 이야기 - Stack 과 Heap

하이.. ! 어느날 회사의 누군가 Java의 메모리가 어떻게 관리되는지에 대해서 물어봤다. 대답이 많이 나오지 않았다... 나름대로 Java를 제일 잘한다고 생각했었고, 자신감도 있던 상태라 충격이 컸

devkingdom.tistory.com

 

오늘은 Heap 영역의 메모리를 청소하는 Garbage Collector 에 대해 알아보려고한다.

 

먼저 GC가 무엇인지부터 말씀드리겠다.

GC는 JVM의 Heap 영역에서 사용하지 않는 객체를 없애주는 프로세스를 의미한다.

 

Heap 영역에는 다양한 객체들이 올라와 있는데 이 객체들 끼리는 서로 참조하여 사용된다. 이렇게 GC는 GC Root 에서 시작해서 각 객체끼리 유효한 참조가 있으면 Reachable 객체, 그렇지 않다면 Unreachable 객체라 판단한다.

 

여기서 객체는 힙내에 있는 다른 객체에 의한 참조가 있을수 있고,

java 스택, 즉 메서드 내의 지역변수나 파라미터들에 의한 참조가 있을수 있고,

JNI에 의해 생성된 객체에 대한 참조가 있을수 있고

메서드 영역의 Static 변수에 의한 참조가 있을 수 있다. 

 

이렇게 시작된 데이터들이 GC Root가 될 수 있다.

 

아래 그림을 보면 무슨말인지 더 이해가 되실거라 본다.

 

여기서 GC의 청소 대상이 되는 것이 바로 Unreachable 이다.

 

GC는 기본적으로 Mark and Sweep 이라는 방식을 거친다. 

 

Mark 는 GC Root 에서 시작해서 모든 변수를 싸악~~ 스캔해서 각각 어떤 객체를 참조하고 있는지 찾아서, 얘는 reachable, 얘는 unreachable 이렇게 마킹하는 과정이라고 생각하면된다.

 

그리고 Sweep 과정에서 unreachable 한 놈들을 날려버린다.

 

그리고 알고리즘에 따라 다르게 Compact라는 것도 동작을 한는데 sweep을 하고나면 군데 군데 뻥뻥뚤려서 객체들이 분산이 되어있을거다. 이때 heap의 시작주소로 쭉 모아서 메모리가 할당된 부분과 안된 부분으로 나누는 과정을 Compact라고 한다. 이 과정은 메모리 단편화를 방지한다.

 

다음은 GC 동작과정에 대해 설명을 드리겠다.

 

GC 동작과정을 보기전에 GC 설계자들의 2가지 가설을 잘 기억하자.

 

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

 

일단 GC를 이해하기 위해서는 Heap 구조를 알아야하는데

Heap은 Young Generation 과 Old Generation 영역 그리고 Meta Space로 나뉜다.

Young Generation 은 새로운 객체들이 할당되는 영역을 의미하고,

Old Generation 은 오랫동안 계속 살아남은 객체들이 있는 영역을 의미한다.

그리고 Meta Space는 gc가 일어날때 필요한 클래스와 메소드의 메타정보가 있는 영역을 의미한다.

 

Young Generation 을 세부적으로 보면 Eden, Survivor 0 ,Survivor 1 영역이 있다.

여기서 새롭게 생성된 객체는 우선 Eden으로 들어온다.

 

여기서 Eden 이 꽉 차면 Minor GC 가 일어난다.

 

먼저 앞서 말씀드렸던 것처럼 Mark 과정이 일어나고

 

Reachable한 녀석들을 Survivor 0 영역으로 이동시킨 뒤,

 

Sweep으로 Unreachable한 녀석들을 싸악 날려버린다.

 

 

여기서 살아남은 객체들의 Age 값은 하나씩 증가한다.

그리고 또 다시 Eden 영역에 값이 할당 되고

 

또 Minor GC가 발생한다.

 Mark 과정에선 Eden 영역 뿐만 아니라 다른 영역의 있는 값에 대해서도 Mark를 진행한다.

 

그러고 Reachable 한 놈들을 이번에는 Survivor 1로 옮긴다.

 

이렇게 반복되다보면 객체의 age값이 특정 임계점에 도달하게 되는데,

 

이때 이 객체들을 Old generation 으로 이동시킨다. (Promoted)

 

이렇게 진행되다가 Old Generation도 꽉 차게되면 여기서 Major GC (Full GC) 가 발생하게 된다.

GC 가 발생하게 되면 Gc 를 수행하는 스레드 이외에 JVM이 모든 스레드의 작업을 중단 시키는데 이걸

stop-the-world 라고한다. 뭔가 영화 제목 같지 않나 ㅎㅎ??

 

여기서 stop-the-world 가 발생하게 되면 어플리케이션이 잠깐 멈추는데 ... Minor GC 같은 경우에는 Stop the world 가 발생하면 잠깐 멈추고 말지만 Major GC는 소요되는 시간이 오래 걸려... 자칫 잘못하면 큰 에러로 이어지는 경우가 있으니 결국 Major gc 가 일어나지 않도록 할 수 밖에 없다. 근데 ... 결국 Major gc가 일어나지 않도록하는건 나는 개발자의 역량이라고 생각한다. 너무 길게 참조, 참조, 참조하는 그런 개발 행위는 ... 좀 버려야 하지 않을까 싶다.

 

GC 의 종류마다 stop the world 가 다 다르게 일어난다. GC의 종류는 아래와 같은데

- Serial GC

- Parallel GC

- Parallel Old GC

- CMS(Concurrent Mark Sweep) GC

- G1(Garbage First) GC

궁금하신 분들은 꼭 검색해서 공부해보시길 권한다.

 

오늘은 간단하게 GC를 정리했다.

 

끝.

 

반응형

'Programming > JAVA' 카테고리의 다른 글

[Java] 멀티 스레드 동시성 제어  (1) 2021.09.02
[Java] Multi Thread 처리  (1) 2021.08.30
Apache Kafka 정리  (1) 2021.08.19
[Java] 람다식 (Lambda Expression)  (0) 2021.08.16
[JAVA] JAVA 메모리 이야기 - Stack 과 Heap  (14) 2021.04.24

댓글