메모리 누수
더 이상 필요 없는 객체에 대한 참조가 의도치 않게 계속 유지되어, 가비지 컬렉터가 해당 메모리를 회수하지 못하는 현상입니다.
발생 원인
- 이벤트 리스너 미해제: DOM 요소에 등록한 이벤트 리스너를 요소를 제거하기 전에
removeEventListener()로 해제하지 않으면, 리스너가 해당 요소를 계속 참조해 메모리가 회수되지 않습니다. - 클로저 오남용: 클로저는 외부 함수의 변수를 기억하는 유용한 기능이지만, 큰 객체나 DOM 요소를 참조하는 클로저가 필요 이상으로 오래 유지되면 가비지 컬렉터가 그 메모리를 회수할 수 없습니다.
- 전역 변수 남용:
window같은 전역 객체에 저장된 변수는 애플리케이션이 종료될 때까지 유지되므로, 불필요한 데이터를 전역 변수로 선언하면 메모리 누수로 이어집니다.
예시
function attachListener() {
const el = document.getElementById('button');
el.addEventListener('click', () => console.log('clicked'));
}
// el을 DOM에서 제거해도 리스너를 해제하지 않으면 참조가 남아 GC 대상에서 제외됨
방지 방법
- 사용이 끝난 이벤트 리스너는
removeEventListener()로 명시적으로 제거합니다. - 클로저가 불필요하게 큰 객체나 DOM 요소를 오래 참조하지 않도록 스코프를 최소화합니다.
- 전역 범위 사용을 최소화하고, 즉시 실행 함수(IIFE)나 모듈 패턴으로 변수의 유효 범위를 제한합니다.
모니터링 방법
크롬 개발자 도구의 Memory 탭으로 확인할 수 있습니다. Heap snapshot으로 특정 시점의 힙 메모리에 어떤 객체가 존재하는지 파악하고, Allocations on timeline으로 시간에 따른 메모리 할당·해제 추이를 추적할 수 있습니다.
핵심 정리
메모리 누수는 이벤트 리스너 미해제, 클로저 오남용, 전역 변수 남용 등으로 불필요한 참조가 계속 유지될 때 발생하며, 참조를 명시적으로 해제하고 스코프를 최소화해 방지할 수 있습니다.