01 · Concept

메모리 관리

JavaScript의 메모리 관리와 가비지 컬렉션을 이해하고, 메모리 릭을 방지하는 패턴을 학습합니다.

JavaScript는 가비지 컬렉션(GC)을 통해 자동으로 메모리를 관리하지만, 이벤트 리스너 미해제, 클로저 참조, 분리된 DOM 노드 등으로 메모리 릭이 발생할 수 있습니다.WeakRef WeakMap을 활용하면 GC 친화적인 코드를 작성할 수 있습니다.

02 · Interactive Demo

메모리 릭 패턴과 해결 시각화

각 메모리 릭 패턴을 선택하고, 문제 발생과 해결 과정을 시뮬레이션하세요.

// ❌ 메모리 릭: 리스너 미해제
function setupHandler() {
  const data = new Array(10000).fill('★');

  const handler = () => {
    console.log(data.length); // 클로저로 data 참조 유지
  };

  document.addEventListener('click', handler);
  // 컴포넌트가 언마운트되어도 handler와 data는 GC 대상 아님!
}

// ✅ 해결: cleanup 함수로 해제
function setupHandler() {
  const data = new Array(10000).fill('★');
  const handler = () => console.log(data.length);

  document.addEventListener('click', handler);

  return () => {
    document.removeEventListener('click', handler);
    // handler 해제 → data도 GC 가능
  };
}
위험도:HIGH
Mark
Sweep
Compact
03 · Code Example

코드 예시

실제 코드로 동작 원리를 확인하세요.

// React 컴포넌트에서의 cleanup
useEffect(() => {
  const controller = new AbortController();

  fetch('/api/data', { signal: controller.signal })
    .then(res => res.json())
    .then(setData);

  const handler = () => console.log('resize');
  window.addEventListener('resize', handler);

  const timer = setInterval(() => tick(), 1000);

  // ✅ cleanup: 모든 비동기 작업 정리
  return () => {
    controller.abort();                        // fetch 취소
    window.removeEventListener('resize', handler); // 리스너 해제
    clearInterval(timer);                      // 타이머 해제
  };
}, []);

// ✅ 전역 참조 관리
let cache = new Map();
function clearCache() {
  cache.clear(); // 명시적 해제
  cache = null;  // 참조 끊기
}
04 · Interview Point

면접 핵심 질문

1. 해제되지 않은 이벤트 리스너 — 등록 후 removeEventListener를 호출하지 않음 2. 클로저의 의도치 않은 참조 — 불필요한 변수를 계속 참조하는 클로저 3. 분리된 DOM 노드 — DOM에서 제거했지만 JS 변수가 참조 유지 4. 전역 변수 — 실수로 전역에 할당된 변수 5. 해제되지 않은 타이머/인터벌 — clearInterval, clearTimeout 미호출 6. 콘솔 로그 — 개발자 도구가 열린 상태에서 console.log의 참조 유지
현대 JavaScript 엔진(V8)은 Mark-and-Sweep 알고리즘을 사용합니다.Mark 단계에서 루트(전역 객체, 스택)에서 시작하여 도달 가능한 모든 객체를 마킹합니다.Sweep 단계에서 마킹되지 않은 객체의 메모리를 해제합니다. V8은 세대별 GC(Generational GC)를 사용하여 Young Generation(Minor GC, Scavenge)과 Old Generation(Major GC, Mark-Sweep-Compact)으로 나누어 효율적으로 관리합니다.
WeakMap은 키 객체가 다른 곳에서 참조되지 않으면 자동으로 GC될 수 있게 합니다. DOM 요소에 메타데이터를 연결하거나, 프라이빗 데이터 저장에 활용합니다.

WeakRef는 객체에 대한 약한 참조를 생성합니다. GC가 해당 객체를 수거해도 에러가 발생하지 않으며, deref()로 확인합니다. 캐시 구현 시 메모리 압박이 있으면 자동으로 정리되는 패턴에 유용합니다.FinalizationRegistry와 함께 사용하여 GC 시 정리 로직을 실행할 수 있습니다.