💡 가비지 컬렉터(GC, Garbage Collector) - JVM에서 메모리 관리를 위해 사용이 되며 ‘더 이상 참조되지 않는 객체들을 자동으로 탐지하고 해제’하는 역할을 수행합니다. 이를 통해 메모리 관리를 효율적으로 처리하며 프로그램 실행 중에 메모리 누수를 방지하고 메모리 사용을 최적화합니다.
- 또한 개발자들은 가비지 컬렉터를 통해 메모리 관리에 대한 직접적인 관여 없이도 안정적인 프로그램을 작성할 수 있습니다. - 가비지 컬렉터는 메모리 영역(Runtime Data Area)에서 중에서 ‘힙 영역(Heap Area)’내에서 이를 관리하고 사용합니다.
[더 알아보기] 💡 가비지 컬렉터에서 참조를 한다는 말은 무슨 의미일까?
- 참조는 프로그램에서 객체 객체 간의 연결을 나타내는 것을 말합니다. 객체가 다른 객체를 참조하면 참조되는 객체는 참조 체인을 통해 계속해서 접근 가능한 상태가 됩니다.
- 가비지 컬렉터는 참조되지 않은 객체를 식별하기 위해 참조 체인을 따라가며 객체들을 스캔합니다. 참조되지 않은 객체는 가비지로 간주되고 회수됩니다.
2) 메모리 영역 내의 가비지 컬렉터
💡 힙 영역(Heap Area) 안에 존재하는 가비지 컬렉터에 대해 어떠한 동작으로 수행을 하는지 확인해 봅니다.
1. 메모리 영역
💡 메모리 영역(Runtime Data Area) 중에서 ‘힙 영역(Heap Area)’ 의 구조는 Young Generation과 Old Generation으로 구성되어 있습니다.
- 메모리 할당 과정에서 새로운 객체를 생성하는 단계입니다. 이 단계에서는 Young Generation 영역에서 새로운 객체가 생성이 되며 이후 가비지 컬렉터는 ‘Eden 영역’에 해당 객체를 할당합니다.
2. Young Genration 내에서 객체 이동: Promotion Inside Young Genration
- 객체 생성 이후 일정 시간이 지나거나 Eden 영역이 가득 차면 가비지 컬렉터는 Eden 영역에 있는 객체들을 스캔하여 참조되지 않은 객체들을 식별하고 메모리에서 해제합니다. 이때 참조되지 않은 객체들은 가비지로 간주되어 회수되며 참조되어 살아남은 객체들은 Survivor 영역으로 이동됩니다.
3. Young Generation에서 Old Genration으로 승격 : Promotion From Young to Old Gernation
- Survivor 영역에 있는 객체들 중 일정한 조건을 충족한 객체들을 Old Generation으로 이동시킴으로써 이루어집니다. 이를 통해 오랫동안 사용되는 객체들은 Old Generation에서 관리되며, Young Generation에서는 주로 단기간만 사용되는 객체들이 관리됩니다.
- JVM에서 발생하는 가비지 컬렉션 작업 중에 일어나는 ‘일시적인 중단’을 의미합니다. 이는 애플리케이션의 모든 스레드를 정지시키는 것을 의미하며 가비지 컬렉션 작업을 위해 힙 메모리를 정리하고 객체의 수명 주기를 관리합니다.
- 메모리 누수와 같은 문제를 예방하고 JVM의 성능을 최적화하기 위해 필요한 작업입니다. (* 추후 가비지 컬렉터의 튜닝 부분에 중요한 작업입니다.) - 일반적으로 백그라운드에서 진행되는 작업이며 애플리케이션의 성능에 큰 영향을 미치지 않습니다 그러나 STW가 길게 지속되거나 너무 자주 발생할 경우 애플리케이션의 응답 시간이 느려질 수 있습니다. 따라서 개발자는 가비지 컬렉션을 최적화하고 STW 시간을 최소화하기 위해 다양한 방법을 고려해야 합니다.
- ‘여러 스레드’에서 컬렉션 작업을 ‘병렬로 작업을 처리’하는 방식을 의미합니다. 해당 과정을 통해 객체의 수명을 추적하고 사용되지 않는 객체를 삭제하여 메모리를 확보합니다
- 병렬 스레드에서 작업을 처리하기에 동시에 여러 작업을 수행하므로 처리 시간이 단일 스레드 방식에 비해 줄어들 수 있으며 다른 애플리케이션 작업과 함께 실행되기도 하며, 대규모 메모리에서 가비지 컬렉션을 수행할 때 성능을 향상될 수 있습니다. - 반대로 병렬 스레드에서 처리가 되므로 CUP 자원을 더 많이 사용하게 될 수 있습니다.
3. 동시 마크 스위프트 가비지 컬렉터 (Concurrent Mark Sweep Garbage Collector, CMS GC)
💡 동시 마크 스위프트 가비지 컬렉터 (Concurrent Mark Sweep Garbage Collector, CMS GC) - 가비지 컬렉션 작업을 애플리케이션의 스레드 작업을 중단하지 않고 동시에 컬렉션 작업을 수행하는 방식을 의미합니다. 이 방식은 대규모 메모리에서도 일시 중단 시간을 최소화할 수 있는 장점이 있습니다.
- 수행과정을 통해 일시 중단 시간을 최소화하면서 가비지 컬렉션 작업을 수행하기에 대규모 메모리에서도 애플리케이션의 응답성을 유지할 수 있습니다. - 그러나 병렬 가비지 컬렉터와 달리 애플리케이션 스레드와 병행하여 작업하기 때문에 일부 CPU 자원을 가비지 컬렉션에 사용하게 될 수 있습니다.
3. 이후, 애플리케이션 스레드를 중단시키고 가비지 객체를 스위핑 하여 메모리를 확보합니다.
4. 중단된 애플리케이션 스레드를 다시 실행하여 가비지 컬렉션 작업을 완료합니다.
3.1. 마크-앤-스위프트(Mark And Sweep) 알고리즘
💡 마크-앤-스위프트(Mark And Sweep)
- 메모리를 할당하는 과정에서 추가적인 정보를 유지하는 방식입니다. 가비지 컬렉터는 메모리 할당 시 객체에 마크(Mark)를 지정하고, 가비지 컬렉션 단계에서 마크되지 않은 객체들을 가비지로 판단하고 회수(Sweep) 하는 방식을 의미합니다.
💡 마크-앤-스위프트(Mark And Sweep) 동작 과정 1. 표시(Mark) 단계
- 이 단계에서는 모든 도달 가능한 객체를 식별하기 위해 루트(root) 객체들을 찾아 탐색합니다. - 루트 객체들은 주로 프로그램의 전역 변수, 스택 변수, 레지스터 등에 저장된 객체들입니다. 이후, 루트 객체들이 참조하는 모든 객체를 재귀적으로 탐색하며 마킹(mark)합니다.
2. 정리(Sweep) 단계
- 이 단계에서는 마킹되지 않은 모든 객체들을 해제합니다.
- 메모리 할당 영역을 스캔하면서 마킹되지 않은 객체들을 발견하면 이들 객체들의 메모리를 해제합니다. 이로써 더 이상 사용되지 않는 객체들이 메모리에서 제거됩니다.
3. 압축(Compacting) 단계
- 가비지 컬렉터는 메모리에서 제거된 객체들로 인해 생긴 빈 공간을 모아서 압축합니다. 이렇게 함으로써 메모리의 단편화를 최소화하고, 연속된 메모리 공간을 확보합니다.
💡 결론적으로, 참조 체인을 따라가며 도달 가능한 객체들을 마크하고, 마크되지 않은 객체들을 가비지로 판단하여 회수하는 방식으로 메모리를 관리합니다.
💡 Garbage-First (G1) 가비지 컬렉터 (Garbage-First Garbage Collector, G1 GC) - 힙을 동일한 크기의 형태로 분할하여 우선순위를 지정한 다음 우선순위에 따라 청크에 대해 병렬 가비지 수집기를 수행하는 방식을 의미합니다.
- 가비지 컬렉션 작업을 일부 영역에서만 수행하고 나머지 영역에서는 계속 작업을 할 수 있도록 하여 일시 중단 시간을 최소화할 수 있습니다. 또한, 가비지 컬렉션 작업을 병렬로 처리하므로 다른 애플리케이션 작업과 함께 실행되어 애플리케이션의 응답성을 유지할 수 있습니다. - 대규모 메모리를 가진 애플리케이션에서 주로 사용되며, 가비지 컬렉션 작업의 일시 중단 시간을 최소화하면서 응답성을 유지하는 것이 중요한 환경에서 효과적입니다.