프로그래밍 언어/Java

Garbage Collector (GC)

snaildeveloper 2025. 6. 10. 13:45

코딩을 하다보면 수 많은 함수 내에서 여러가지 변수와 객체들을 선언 및 생성하여 사용한다.

fun main(){
    val obj = Something()
}

class Something{}

Java의 객체는 JVM 가상 메모리 영역 중 Heap 영역에 저장이 된다.

서버 또는 애플리케이션 등 실행 과정에 있어 수 많은 객체들을 사용하게 되는데 사용 후 더 이상 사용하지 않는, 참조되지 않는 객체들은 메모리 누수(Memory Leak)를 방지하기 위해 개발자가 직접 메모리에서 회수해야 한다.

하지만 모든 사람은 실수를 하듯, 모든 객체를 완벽하게 관리하기란 불가능에 가깝다.

Java에는 사용하지 않는 객체를 자동으로 메모리에서 회수해주는 Garbage Collector가 존재한다.

 

JVM 메모리

다음과 같은 코드를 실행하면 JVM Stack과 Heap에서는 아래와 같은 일이 일어난다.

fun main(){
    val obj = Something()
    test()
    ...
}

private fun test(){
    val obj2 = Something2()
}

객체를 생성하면 Heap 영역에는 객체의 정보가 Stack 영역에는 객체의 주소가 올라간다.

Stack을 통해 Heap 영역에 있는 객체에 접근하여 사용 후 사용이 완료되면 Stack 영역의 정보가 pop 된다.

Stack 영역에서는 사라졌지만 Heap 영역에는 객체의 정보가 그대로 남아있는데, Garbage Collection은 이처럼 메모리 누수를 일으키는 객체들을 찾아 제거해준다.

 

Mark & Sweep 알고리즘

그렇다면 GC는 어떻게 Heap 메모리 내에서 사용하지 않는 객체를 찾는걸까?

 

Stack 메모리와 같은 Root Space를 통해 사용 중인 객체를 Mark하고 최종적으로 Mark되지 않은 Sweep 객체들을 정리한다.

JVM Heap 구조

GC를 좀 더 효율적으로 작업하기 위해 JVM Heap은 다음과 같은 구조로 이루어져 있다.

Minor GC

Minor GC는 Yong 영역에 속하며 Eden과 Survivor가 있다. 해당 영역은 생성된지 얼마 되지 않은 객체들이 주로 위치한다.

  • Eden : 객체가 처음 생성되면 Eden에 위치한다.
    • 생성한 객체가 많아져 Eden이 차게 되면 Minor GC를 실행
    • GC 이후 남은 객체는 Survivor로 이동
  • Survivor : Survivor는 2개로 이루어져 있고, 둘 중 하나는 무조건 비어있어야 한다.
    • Eden에서 넘어온 객체가 S0으로 배치되었다면 다음 .Minor GC 이후에는 Eden + S0의 객체를 S1으로 이동시켜 S0의 메모리를 비워준다.
    • S1에 객체가 있는 경우에는 다음 GC 때 S0로 이동
    • 위와 같은 방법으로 Survivor의 한 곳은 항상 빈 상태를 유지한다.

 

Major GC (Full GC)

Major GC는 Old Memory 영역에 속하며 Minor GC에서 오랫동안 살아남은 객체는 Old Memory 영역으로 이동하게 된다.

Yong Memory의 경우 메모리의 크기가 크지 않아 Minor GC가 0.5초 이내의 빠른 속도로 처리되어 큰 문제가 생기지 않지만 Old Memory의 경우 가득 차 .Major GC가 발생하게 되면 처리 속도가 느려 처리하는 동안 애플리케이션이 중단되는 Stop-the-world가 발생한다. 따라서 Full GC를 관리한는 것이 중요하다.

 

Full GC를 처리하기 위한 알고리즘

  • Serial GC
  • Parallel GC
  • Parallel Old GC (Parallel Compacting Collector)
  • Concurrent Mark Sweep (CMS)\
  • G1 GC

GC는 메모리 누수(Memory Leak)를 어느 정도 해결해주긴 하지만 완벽하게 해결해주진 않는다.

따라서 Heap 메모리로 인한 성능 저하는 어떻게든 일어날 수 있기 때문에 개발자는 어디서 메모리 누수가 발생하는지 분석하고 해결 할 수 있어야 한다. (Heap Dump)