[JS] 자바스크립트 메모리 관리

Zain·2025년 1월 18일
post-thumbnail

가비지 컬렉션과 메모리 누수에 대해서 명확하게 이해하고 싶어서 작성하는 글


메모리 할당과 해제

자바스크립트에서 변수, 함수, 객체 등을 생성할 때, 자바스크립트 엔진은 이 데이터를 저장할 메모리를 자동으로 할당함.
이후, 더 이상 사용되지 않는 데이터는 가비지 컬렉션(Garbage Collection)을 통해 메모리에서 해제됩니다.


가비지 컬렉션이란?

가비지 컬렉션은 자바스크립트 엔진이 사용하지 않는 데이터를 자동으로 메모리에서 해제하는 방식임.
프로그램에서 더 이상 필요하지 않은 데이터는 가비지 컬렉션을 통해 메모리에서 제거되어 메모리 누수를 방지함.

1. 동작 원리

가비지 컬렉션은 도달 가능성(Reachability)이라는 개념을 바탕으로 작동함.
도달 가능한 데이터는 계속 메모리에서 유지되고, 도달 불가능한 데이터는 메모리에서 해제됨.

  • 도달 가능한 데이터
    • 전역 객체(window, global)
    • 현재 실행 중인 함수의 지역 변수와 매개변수
    • 클로저에서 참조 중인 변수

도달 불가능 데이터

  • 더 이상 코드에서 접근할 수 없는 데이터는 도달 불가능 상태가 되고, 가비지 컬렉션에 의해 제거됨

2. 가비지 컬렉션이 메모리를 제거하는 과정

  1. 도달 가능 데이터 탐색:

    • 루트 객체(예: 전역 객체)에서 시작해, 참조를 따라가며 도달 가능한 데이터를 찾음.
  2. 도달 불가능 데이터 탐지:

    • 도달 불가능한 데이터는 더 이상 참조되지 않으므로, 메모리에서 제거됨.

3. 가비지 컬렉션의 예시

let obj = { key: "value" }; // 객체 생성
obj = null; // 참조 제거, 객체는 가비지 컬렉션 대상
  • 위 예시에서 obj가 더 이상 참조되지 않으면 가비지 컬렉션에 의해 해당 객체는 메모리에서 해제됨.

메모리 누수란

메모리 누수는 더 이상 사용되지 않는 메모리가 해제되지 않고 계속 메모리에서 남아 있는 상태.
이로 인해 불필요한 메모리가 계속 차지하고, 성능 저하를 유발할 수 있음.

1. 메모리 누수의 원인

메모리 누수는 주로 참조가 끊어지지 않은 채로 객체가 메모리에서 해제되지 않는 경우 발생.

불필요한 전역 변수

전역 변수에 불필요한 객체나 값이 계속 저장되면 해당 객체는 해제되지 않고 계속 메모리에 남음.

let globalObject = { name: "John" }; // 전역 변수로 객체 저장
  • 더 이상 사용되지 않지만 객체는 계속 메모리에 존재

이벤트 리스너로 인한 메모리 누수

발생 이유

이벤트 리스너는 특정 DOM 요소에 이벤트가 발생할 때 실행될 콜백 함수를 추가하는 역할을 함

  • 이벤트 리스너가 등록되면 해당 DOM 요소와 콜백 함수가 연결된다.
  • 콜백 함수는 힙에 저장되고, DOM 요소가 더 이상 화면에 표시되지 않거나 더 이상 사용되지 않더라도, 이벤트 리스너는 해당 콜백 함수를 계속 참조하므로, 메모리에서 해제되지 않는다.
  • 화면이 전환되거나 DOM 요소가 제거되었는데도 이벤트 리스너가 제거되지 않으면, 해당 콜백 함수가 계속 힙에 남아서 메모리 누수가 발생할 수 있다.
// 1. 이벤트 리스너 제거
const button = document.querySelector('button');
button.addEventListener('click', () => {
  console.log("Button clicked");
});

button.removeEventListener('click', handleClick);

// 2. once 옵션 사용 (한번만 실행되고 제거)
button.addEventListener('click', () => {
  console.log("Button clicked");
}, { once: true });

메모리 누수의 본질

메모리 누수는 힙(Heap)에 저장된 객체에 대한 참조가 스택(Stack)에서 계속 유지되면서 객체가 해제되지 않고 남아있는 경우.

힙(Heap)과 스택(Stack)의 역할

  • 힙(Heap): 객체나 배열 같은 동적 메모리 할당이 이루어지는 영역. JavaScript에서 객체나 배열 생성하면 그 데이터는 힙에 할당됨.
  • 스택(Stack): 함수 호출, 변수 선언 등 지역 변수들이 저장되는 메모리. 함수 종료되면 지역 변수는 스택에서 사라짐. 하지만 힙에 저장된 객체를 참조하는 참조 변수는 스택에 저장됨.

메모리 누수의 발생 과정

  1. 참조 유지
    객체가 힙에 저장되면, 그 객체를 참조하는 변수가 스택에 저장됨.

  2. 참조가 끊어지지 않음
    객체가 더 이상 필요 없거나 사용되지 않아도, 스택에 있는 참조 변수는 여전히 객체를 가리킬 수 있음.

  3. 객체가 해제되지 않음
    객체는 여전히 스택에서 참조되고 있기 때문에 가비지 컬렉션이 객체를 해제하지 못함. 실제로는 더 이상 사용되지 않지만, 참조 변수로 인해 메모리에서 해제되지 않는 상태가 됨.

profile
Vue, Laravel | TS, JS, PHP, MySQL

0개의 댓글