메모리 누수의 본질: 자동 관리의 한계
메모리 누수는 애플리케이션이 더 이상 필요하지 않은 객체에 대한 참조를 의도치 않게 유지함으로써 발생합니다. 가비지 컬렉터는 더 이상 도달할 수 없는(unreachable) 객체만 제거하므로, 프로그램 코드에서 참조가 계속 존재하면 메모리를 해제할 수 없습니다. JVM 환경에서 이는 시간이 지남에 따라 누적되어 결국 OutOfMemoryError를 유발하고 GC 일시 중단 시간의 증가로 성능 저하를 초래합니다.
도달 가능성 분석과 마크-스윕 알고리즘
현대 가비지 컬렉터는 마크-스윕(Mark-Sweep) 기법을 기반으로 작동합니다. 마크 단계에서 스택, 정적 변수, 레지스터 등 프로그램 루트로부터 깊이 우선 탐색으로 모든 도달 가능한 객체를 표시합니다. 스윕 단계에서는 표시되지 않은 모든 객체를 힙에서 제거하고 메모리를 회수합니다. 이 과정에서 "stop-the-world" 일시 중단이 발생하므로, 장시간 실행되는 애플리케이션에서는 GC 성능 튜닝이 중요합니다.
메모리 누수 패턴과 진단
실무에서 자주 발생하는 누수는 정적 참조, 닫지 않은 리소스(스트림, DB 커넥션), 컬렉션의 무제한 성장, 리스너 등록 해제 누락입니다. 진단 도구로는 Java Flight Recorder(JFR), VisualVM, 힙 덤프 분석이 사용됩니다. GC 로그를 분석할 때 전체 GC 후에도 메모리가 줄지 않거나, 초당 98% 이상이 GC에 소비되면 누수 가능성이 높습니다. 예방 원칙은 WeakReference 활용, try-with-resources 패턴, 명시적 리소스 정리입니다.