메모리 누수(Memory Leak)는 왜 발생할까?

메모리 누수란 무엇인가

메모리 누수는 프로그램이 더 이상 사용하지 않는 메모리를 계속 점유한 채 반환하지 않는 현상을 말합니다. 마치 도서관에서 책을 빌린 뒤 다 읽고도 반납하지 않는 것과 비슷합니다. 책 한 권 정도는 문제가 되지 않지만, 이런 일이 계속 쌓이면 결국 도서관에 새 책을 꽂을 공간이 사라지듯, 프로그램도 사용 가능한 메모리가 점점 줄어들다가 결국 느려지거나 다운됩니다.

메모리 누수가 발생하는 원리

대부분의 현대 언어(Java, JavaScript, Python 등)는 가비지 컬렉터(GC)가 더 이상 참조되지 않는 객체를 자동으로 정리해줍니다. 문제는 개발자가 의도치 않게 불필요한 참조를 계속 남겨두는 경우입니다. GC는 ‘참조가 남아있는 객체’는 절대 지우지 않기 때문에, 참조만 살아있다면 실제로는 쓰지 않는 객체라도 메모리에 계속 남게 됩니다.

대표적인 예시는 다음과 같습니다.

  • 전역 변수나 캐시에 객체를 계속 추가만 하고 제거 로직이 없는 경우
  • 이벤트 리스너를 등록만 하고 해제(removeEventListener)하지 않는 경우
  • 사용이 끝난 커넥션(DB, 파일, 소켓)을 닫지 않는 경우
  • 클로저가 큰 객체를 계속 참조하고 있어 GC 대상에서 제외되는 경우

예를 들어 자바스크립트에서 버튼 클릭 이벤트를 등록한 컴포넌트를 화면에서 제거하면서도 리스너를 해제하지 않으면, 해당 컴포넌트 객체는 이벤트 리스너를 통해 여전히 참조되고 있어 GC가 수거하지 못합니다. 결과적으로 화면 전환이 반복될 때마다 안 쓰는 컴포넌트들이 메모리에 계속 쌓이게 됩니다.

실무에서 왜 신경 써야 하는가

메모리 누수는 짧은 테스트에서는 잘 드러나지 않고, 장시간 운영되는 서버나 앱에서 서서히 문제가 커진다는 점이 무섭습니다. 처음엔 정상적으로 동작하다가 며칠 뒤 서버 응답이 느려지거나, 결국 OutOfMemoryError로 서비스가 중단되는 식으로 나타납니다. 그래서 실무에서는 힙 덤프 분석, 프로파일링 도구(Chrome DevTools Memory 탭, Java의 VisualVM 등)를 활용해 주기적으로 메모리 사용 추이를 점검합니다.

결국 메모리 누수를 막는 핵심은 ‘내가 만든 참조를 다 쓰고 나면 반드시 정리한다’는 습관입니다. 리소스를 열었으면 닫고, 이벤트를 등록했으면 해제하고, 캐시를 쓴다면 크기 제한이나 만료 정책을 두는 것이 안정적인 서비스 운영의 기본입니다.

댓글 남기기