[Java를 실행하면 어떻게 진행이 되나요?] 2-4. Garbage Collector

khyojun·2022년 12월 1일
3
post-thumbnail

🔍 Java 실행 과정

오늘은 4번째 Garbage Collector에 대해서 알아보자.

  • ✔ Class Loader
  • ✔ Execution Engine
  • ✔ Runtime Data Area
  • Garbage Collector

✔ 시작하기에 앞서 알아 볼 stop-the-world

stop-the-world란, GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것이다. stop-the-world가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다. GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다. 어떤 GC 알고리즘을 사용하더라도 stop-the-world는 발생한다. 대개의 경우 GC 튜닝이란 이 stop-the-world 시간을 줄이는 것이다.

위 글을 보면 stop-the-world라는 과정은 GC를 진행하는데 발생이 하게 되며 말 그대로 세계를 멈춘다 라는 말처럼 GC를 실행하면 쓰레드를 제외한 나머지 쓰레드의 모든 작업을 멈추게 된다는 거다. 완료하고 이후에 중단했던 작업을 다시 시작한다는 것이다.
그래서 GC튜닝이라는 것은 이렇게 멈추는 과정에 대한 시간을 줄여나가는 것이 튜닝한다고 하는 것을 알 수 있다.

📌 Garbage Collector

C/C++에서 프로그래머는 객체의 생성과 파괴를 모두 담당합니다. 일반적으로 프로그래머는 쓸모없는 객체의 파괴를 무시합니다. 이러한 부주의로 인해 특정 시점에서 새 개체를 만드는 데 충분한 메모리를 사용할 수 없으며 전체 프로그램이 비정상적으로 종료되어 OutOfMemoryErrors 가 발생할 수 있습니다.
그러나 Java에서는 프로그래머가 더 이상 사용하지 않는 모든 객체를 돌볼 필요가 없습니다. Garbage Collector는 이러한 객체를 파괴합니다.

🔍 요약하면?

C/C++ 과는 달리 Java에서는 프로그래머가 더 이상 사용하지 않는 모든 객체를 돌보지 않아도 되는데 Garbage Collector가 이런 객체들을 파괴한다.

🏸 요약만 하기에 알아볼게 더 있다.

그러면 이 Garbage Collector가 어떻게 작동하는지는 조금이라도 알아보자.

✔ 어떻게 GC(Garbage Collector)가 만들어졌을까?

두 가지 가설 하에 만들어졌다고 한다.
1. 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다.
2. 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
이런 가설을 이것을 'weak generational hypothesis' 이라고 부른다.

쓰레기를 확인하고 쓸고 Mark and Sweep

Garbage Collection 과정은 Mark and Sweep 이라고도 하는데 JVM의 Garbage Collector 가 스택의 모든 변수를 스캔하면서 각각 어떤 오브젝트를 참조 하고 있는지 찾는과정이 Mark라고 한다. Reachable 오브젝트가 레퍼런스하고 있는 오브젝트 또한 marking 한다. 그러면? Unreachable한 오브젝트를 Sweep 쓸어버린다고 한다.

Reachable? Unreachable?

Garbage Collector는 객체를 Reachable과 Unreachable의 상태로 구분한다. 구분하는 방법은 Root set 과의 관계로 판단한다. Root set으로부터 어떤 식으로든 Reference 관계가 있다면 Reachable Object라고 판단하고, 그렇지 않다면 Unreachable Object라고 판단한다. Root set을 간단하게 설명하면 객체들 간의 참조 사슬의 시작점이라고 생각하면 된다.
Root set은 아래의 세 가지 형태로 나뉜다.

  • JVM Stack 내의 Local Variable Section과 Operand Stack에서의 참조
    (Java 메소드 내에서 실행하는 지역 변수 또는 파라미터에 의한 참조)
  • JVM Method Area의 Constant pool에서의 참조 (정적 변수에 의한 참조)
  • 아직 메모리에 남아 있는 Native Method로 넘겨진 Object에서의 참조(JNI에 의해 생성된 객체에 대한 참조)

위의 세 가지 형태의 Root set으로부터 이어진 참조 사슬에 포함되어 있으면 Reachable Object이고 그렇지 않은 것은 Unreachable Object이다.

요약

즉, 위 검증 과정에서 참조가 되버리면 Reachable, 아니면 Unreachable인데 이러한 확인 과정을 Mark라고 하고 이렇게 분류한 정보를 바탕으로 Unreachable를 Sweep(쓸어버린다)한다고 한다.

📌 5가지로 나눠지는 부분

Heap Area 에서는 참조되지 않는 인스턴스와 배열에 대한 정보 또한 얻을 수 있기 때문에 GC 의 주 대상이기도 한다. 이때, 인스턴스가 생성된 후 시간에 따라서 다음과 같이 5가지 부분으로 나눌 수가 있다.

Eden, Survivor 2개 , Old , Perm 으로 나누어지게 된다.
이 중 Young Generation이라고 불리는 친구들은 Eden, Survivor 까지 Old Generation은 Old, Perm 부분이라고 할 수 있다.

여기서 Old, Young은 위에 간단히 말한 'weak generational hypothesis' 를 의거하여 Young 영역과 Old 영역으로 메모리를 분할하여, 새롭게 생성되는 객체는 Young 영역에 보관하고, 점차 나이를 들게 한 다음 어느정도 나이를 먹은 객체는 Old 영역에 보관하는 알고리즘을 고안해냈다고 한다.

📕 Young Generation

Young Generation에서의 과정은 다음과 같다.

  • 새로 생성한 대부분의 객체는 Eden 영역에 위치한다. Eden 영역이 꽉 차면 GC가 실행하게 된다.
  • Eden 영역에서 GC가 한 번 발생한 후 살아남은 객체는 Survivor 영역 중 하나로 이동된다.
  • Eden 영역에서 GC가 발생하면 이미 살아남은 객체가 존재하는 Survivor 영역으로 객체가 계속 쌓인다.
  • 하나의 Survivor 영역이 가득 차게 되면 그 중에서 살아남은 객체를 다른 Survivor 영역으로 이동한다.
    (그리고 가득 찬 Survivor 영역은 아무 데이터도 없는 상태로 된다.)
  • 이 과정을 반복하다가 계속해서 살아남아 있는 객체는 Old 영역으로 이동하게 된다.

이 절차를 확인하게 되면 Survivor라는 영역이 2개가 있는데 그 중 하나는 비어 있는 상태로 남아야 한다.
(약간 2개가 있는 이유는 가득 찰 경우 넘겨줄 공간이 필요하기 때문에 존재하는 거 같다.)
그래서 만약 이 두 영역이 둘 다 가득 차있거나 사용량이 0이 된다면 시스템이 정상적이지 않는 상황이라고 한다.

그리고 여기서 일어나는 GC를 바로 Minor GC라고 한다.

📕 Old Generation

Old 영역은 기본적으로 Old 영역에 데이터가 가득 차면 GC를 실행한다.

  • Old 영역에 있는 모든 객체들을 검사하며 참조되고 있는지 확인한다.
  • 참조되지 않은 객체들을 모아 한 번에 제거한다.
  • Minor GC보다 시간이 훨씬 많이 걸리고 실행중에 GC를 제외한 모든 쓰레드가 중지한다.
    - 참고 : Permanent 의 경우에는 클래스의 메타 정보 및 static 변수를 저장하고 있는데, Java 8 버전 이후로 Native 영역에 존재하는 Metaspace 라는 영역으로 대체가 되었다고 한다.

그리고 여기서 일어나는 GC를 바로 Major GC라고 한다.

그래서 위에 있는 Minor GC, Major GC를 각각 알아보게 되었는데 다음과 같은 과정에 의해서 Garbage Collector가 동작을 한다는 것을 일단 알 수 있었다.

🔍 Minor GC, Major GC 정리

  • 이름을 Minor GC, Major GC라고 지어진 이유는 Major GC에서 상대적으로 더 주요하게 GC가 진행되기에 이름이 이렇게 지어졌다.

Minor GC

  • 대상: Young Generation
  • 속도: 빠름
  • 실행시점: Eden 영역이 가득 찼을 때

Major GC

  • 대상 : Old Generation
  • 속도 : 느림
  • 실행시점 : Old 영역이 꽉차게 된 경우

JVM 기능 정리 글

  • ✔ Class Loader
  • ✔ Execution Engine
  • ✔ Runtime Data Area
  • ✔ Garbage Collector

이제 다음글은 실제로 어떻게 동작하는지 나열해 볼 차례!

출처

profile
코드를 씹고 뜯고 맛보고 즐기는 것을 지향하는 개발자가 되고 싶습니다

0개의 댓글