프로그래밍을 하다보면 아무조 참조하지 않는 메모리인 가비지(Garbage) 가 발생하게 됩니다.
Person p1 = new Person("Yoon");
Person p2 = new Person("Lee");
p1 = null; // Person("Yoon") -> 접근 불가능 상태
p2 = null; // Person("Lee") -> 접근 불가능 상태
C언어의 경우 위의 메모리를 free() 메소드를 통해 직접 해제해 주어야 했습니다. 그러나 Java의 경우 이러한 작업을 가비지 컬렉터가 가비지 컬렉션 을 통해 자동으로 처리해줍니다.
보통 가비지 컬렉션이 진행되는 과정을 간단하게 설명하면 Mark 와 Sweep 으로 이루어집니다.
GC은 이러한 두 과정을 동시에 진행하지 않고, 실행되고 있는 프로그램이 여건에 따라 Mark 하고 이후에 Sweep을 따로 처리하기도 합니다.
Mark
접근 불가능 상태(Unreachable) 상태의 인스턴스들을 하나한 체크해 놓는 과정입니다.
Sweep
이렇게 체크되어 있는 인스턴스(가비지)들을 이후에 한번에 삭제하는 과정을 Sweep이라고 합니다.
System.gc(); // JVM에게 가비지 컬렉션을 수행해달라고 요청
System.runFinalization(); // 까지 입력하면 왠만하면 gc가 일어나기는 함
프로그래머가 직접 가비지 컬렉션을 수행하달라고 요청 할 수는 있습니다. (명령이 아니라 요청 JVM은 프로세스 수행에 여유가 있을 경우 gc를 우선으로 실행시켜줌)
❌ 그러나 이러한 가비지 컬렉션을 직접 호출하는 행위는 시스템의 성능에 큰 영향을 미치기 때분에 절대 호출해서는 안됩니다.
가비지 컬렉션에 대해 더 자세히 알아가기전에 짚고 넘어가야 할 용어가 있습니다.
stop-the-world란 GC가 발생할때 JVM 이 GC를 실행하기 위해 실행중이던 프로그램을 멈추는 시간입니다. GC의 성능을 향상 시킨다는 것은 stop-the-world의 시간을 얼마나 줄이냐 라고 할 수 있습니다.
- 대부분의 객체는 금방 접근 불가능 상태(unreachable)가 된다.
- 오래된 객체에서 젊은 객체로의 참조는 아주 적게 존재한다.
이러한 두 가설을 바탕으로 가비지 컬렉션의 성능을 고려하여 Hotspot JVM 에서는 크게 힙 영역을 2개의 물리적 공간으로 나누었습니다. 바로 Young 영역 과 Old 영역 입니다. 또한 가비지 컬렉션은 해당 두 영역을 따로 처리(Mark & Sweep) 하여 stop-the-world 시간을 최소화 합니다.
각각의 영역이 청소될 때 Minor GC, Major GC 가 발생한다고 이야기 합니다.
위 그림을 보면, 대부분의 인스턴스는 생성되고 오랜 시간이 지나지 않아 접근 불가능 상태(Unreachable)가 된다는 사실을 확인 할 수 있습니다.
GC이 전체 모든 인스턴스가 삭제 대상인지 체크하는 것은 너무 오랜시간이 소요되는 일이기에 생성된지 얼마 되지 않아 삭제될 가능성이 높은 인스턴스들과 그렇지 않은 인스턴스를 영역으로 구분해 각각 GC를 수행하기 위함 입니다.
Young 영역 (Young Generation 영역)
=> 새롭게 생성된 객체가 주로 저장되는 영역입니다. 대부분의 객체는 금방 접근 불가능 상태가 된다는 가설에 따라 대부분의 객체는 이 영역에서 생성되고 소멸되고를 반복합니다.
그러나 이 영역에서 접근 가능 상태(Reachable)를 유지하다 보면 Old 영역으로 데이터가 넘어가게 됩니다.
Young 영역이 GC이 발생하는 경우 Minor GC이 일어난다고 합니다.
Old 영역 (Old Generation 영역)
=> 접근 불가능상태(Unreachable) 상태가 되지 않고 Young 영역에서 살아남은 객체들이 복사되는 영역입니다.
대부분 Young영역보다 크게 할당되고, 크기가 큰 만큼 GC가 자주 일어나지는 않습니다. (이미 오래 참조를 이어가고 있어 어느정도 입증도 되었기 때문)
Old 영역이 GC이 발생하는 경우 Major GC이 일어난다고 합니다.
GC의 전체적인 흐름을 이해하기 위해 Young 영역과 Old 영역에 대해 더욱 자세히 살펴봅시다.
- Eden 영역
- 두 개의 Survival 영역
Young 영역은 3개의 영역으로 구분되어 있습니다.
객체가 처리되는 절차에 대해 이야기 해보자면,
우선 새로 생성한 객체는 Eden 영역에 위치하게 됩니다. 그리고 시스템이 실행되며 Eden 영역은 점점 채워지게 되고 전부 채워지는 순간, 접근 불가능한 상태의 인스턴스들을 체크하고(Mark) 이후 해당 인스턴스들을 삭제(Sweep)하게 됩니다. 남은 인스턴스들을 압축하여 나이(age)를 +1 해주고 Survival 영역 중 비어있는 영역에 이동시킵니다.
이후 이러한 과정을 반복하면서 나이를 계속 먹어가는 인스턴스가 생기고,
정해진 임계점을 넘어가게 되면 Old 영역으로 인스턴스가 넘어가게 됩니다. 이것을 Promotion 이라고 합니다.위의 예시에서는 9를 임계점으로 잡았는데 Hotspot JVM 에서는 기본으로 31이 Promotion 임계 값이라고 합니다.
Old 영역의 경우도 기본적으로 데이터가 가득 차면 GC를 실행합니다. GC 방식에 따라 처리 절차가 달라진다고 하는데, 우선 GC 방식으로는 여러가지가 있지만 그중에
ZGC의 경우 최근 관련 글이 하나 올라와서 대충 봤었는데 오늘은 다른 공부할게 또 많아서 여기까지만 정리하고 나중에 다시 정리해보는 걸로 하려고 합니다..