가비지 콜렉션(Garbage Collection, GC)은 자동 메모리 관리의 한 형태로, 프로그램이 동적으로 할당했지만 더 이상 사용되지 않는 메모리를 자동으로 회수하는 기능을 의미합니다. 이 기능은 Java와 같은 고급 언어에서 흔히 볼 수 있는 중요한 기능입니다.
Java에서는 객체를 생성할 때마다 메모리가 할당되며, 이 메모리 공간은 '힙'이라는 영역에 할당됩니다. 그러나 객체가 더 이상 필요하지 않게 되거나 참조되지 않게 되면, 그 메모리는 사실상 '가비지'가 됩니다.
다음은 가비지 콜렉션의 기본 원리를 설명한 것입니다:
Mark: 가비지 콜렉터는 힙 내의 모든 객체들을 검사하며 각 객체가 '사용 가능'한지, 아니면 '가비지'인지를 표시합니다. '사용 가능'한 객체는 아직 프로그램에서 참조되고 있는 객체를 의미하며, '가비지'는 더 이상 참조되지 않는 객체를 의미합니다.
Sweep: 이 과정에서 가비지 콜렉터는 표시된 '가비지'를 힙에서 제거하고, 그 메모리를 회수합니다. 이렇게 해서, 메모리는 효과적으로 관리되고, 메모리 누수가 방지됩니다.
Compact: 가비지가 제거되면 남은 객체들 사이에 여유 공간이 생깁니다. 따라서, 남은 객체들을 이동시켜서 연속적인 메모리 공간을 만들고 힙의 공간을 최적화합니다.
자바의 가비지 콜렉션은 프로그래머에게 메모리 관리 부담을 덜어주며, 메모리 누수와 같은 일부 문제를 방지할 수 있습니다. 그러나 GC의 실행 시점은 JVM에 의해 결정되므로, 가비지 콜렉션이 언제 일어날지, 얼마나 오래 걸릴지를 정확하게 예측하거나 제어하는 것은 어렵습니다. 이로 인해 GC가 예기치 않게 발생하면 성능 저하를 가져올 수 있습니다. 따라서 효과적인 시스템 설계와 튜닝을 위해서는 가비지 콜렉션의 동작 방식을 이해하는 것이 중요합니다.
Java의 가비지 컬렉션은 크게 두 가지 영역인 Young Generation과 Old Generation으로 나뉘어 관리됩니다. 이 두 영역은 각각 다른 방식으로 가비지 컬렉션을 처리합니다.
Young Generation: 객체가 처음 생성될 때 이 영역에 할당됩니다. 이 영역은 또 다시 세 개의 영역으로 나뉘어집니다: Eden 영역과 두 개의 Survivor 영역(S0, S1). 객체가 처음 생성되면 Eden 영역에 들어갑니다. 가비지 컬렉션(GC)이 일어나면 살아남은 객체들은 Survivor 영역 중 하나로 이동합니다. 이후에도 계속 살아남는 객체들은 계속해서 Survivor 영역 사이를 이동하게 됩니다.
Old Generation: 객체가 Young Generation에서 존재하다가 일정 시간이 지나면 Old Generation으로 이동하게 됩니다. 이 영역은 상대적으로 가비지 컬렉션의 빈도가 낮으며, 크기도 Young Generation보다 훨씬 큽니다. 이 영역의 GC를 Major GC라고 부릅니다.
Minor GC vs Major GC: Young Generation에서 일어나는 GC를 Minor GC라고 하며, Old Generation에서 일어나는 GC를 Major GC라고 합니다. Minor GC는 빈번하게 발생하지만 처리하는 데 시간이 적게 걸립니다. Major GC는 덜 빈번하게 발생하지만 처리 시간이 오래 걸립니다.
가비지 컬렉션의 알고리즘은 다양하며, 사용하는 JVM에 따라 선택할 수 있습니다. 대표적인 알고리즘으로는 Mark-and-Sweep, Copy, Generational 등이 있습니다. 이 알고리즘들은 각각 메모리를 어떻게 회수하고, 어떤 객체를 가비지로 판단할지에 따라 다릅니다.
메모리는 한정된 리소스이며, 프로그램이 계속 실행되면서 메모리에는 새로운 객체들이 계속해서 생성되고 사용되지 않는 객체들이 계속 쌓입니다. 만약 사용되지 않는 객체를 정리하지 않으면 시간이 지나면서 사용 가능한 메모리 공간이 줄어들고 결국에는 메모리 부족 문제가 발생할 수 있습니다. 이런 문제를 해결하기 위해 사용되지 않는 객체를 메모리에서 제거하는 것이 필요하고, 이를 자동으로 해주는 기능이 바로 가비지 컬렉션입니다.
Java의 가비지 컬렉션은 편리하지만, 한편으로는 성능에 부정적인 영향을 미칠 수도 있습니다. 가비지 컬렉션이 동작하는 동안에는 해당 메모리 영역에 새로운 객체를 할당할 수 없기 때문에, 가비지 컬렉션 동작 시간 동안에는 프로그램의 성능이 떨어질 수 있습니다. 이런 이유로 가비지 컬렉션의 동작 시간과 빈도를 최적화하는 것이 중요합니다.
또한, 가비지 컬렉션의 동작 방식과 최적화 방법은 사용하는 JVM과 가비지 컬렉션 알고리즘에 따라 달라질 수 있으므로, 사용하는 환경에 맞는 가비지 컬렉션 전략을 선택하고 이해하는 것이 중요합니다.