티스토리 뷰

JavaScript

메모리 누수 원인

hjkang 2026. 2. 3. 21:08

메모리 누수란?

더 이상 사용하지 않는 메모리가 해제되지 않고 계속 쌓이는 현상

 

 

증상

- 페이지가 점점 느려짐

- 탭을 오래 켜두면 브라우저 멈춤

- 모바일에서 앱이 강제 종료됨

 

 

주요 원인

1. Event Listener 정리 X

// 메모리 누수
export default {
  mounted() {
    window.addEventListener('scroll', this.handleScroll);
  }
  // 컴포넌트 파괴 시 이벤트 리스너가 남아있음!
}

// 올바른 방법
export default {
  mounted() {
    window.addEventListener('scroll', this.handleScroll);
  },
  unmounted() {
    window.removeEventListener('scroll', this.handleScroll);
  }
}

 

Vue3

import { onMounted, onUnmounted } from 'vue';

export default {
  setup() {
    const handleScroll = () => {
      console.log('scrolling');
    };

    onMounted(() => {
      window.addEventListener('scroll', handleScroll);
    });

    onUnmounted(() => {
      window.removeEventListener('scroll', handleScroll);
    });
  }
}

 

2. Timer 정리 X

// 메모리 누수
export default {
  mounted() {
    setInterval(() => {
      this.updateData();
    }, 1000);
  }
}

// 올바른 방법
export default {
  data() {
    return {
      timer: null
    };
  },
  mounted() {
    this.timer = setInterval(() => {
      this.updateData();
    }, 1000);
  },
  unmounted() {
    if (this.timer) {
      clearInterval(this.timer);
      this.timer = null;
    }
  }
}

 

Composable

// composables/useInterval.js
import { onUnmounted } from 'vue';

export const useInterval = (callback, delay) => {
  const timer = setInterval(callback, delay);
  
  onUnmounted(() => {
    clearInterval(timer);
  });
  
  return timer;
};

// 사용
setup() {
  useInterval(() => {
    console.log('tick');
  }, 1000);
}

 

3. DOM 참조 보관

// 메모리 누수
const elements = [];

document.querySelectorAll('.item').forEach(el => {
  elements.push(el); // DOM 요소가 제거되어도 참조가 남아있음
});

// 올바른 방법 - WeakMap/WeakSet 사용
const elements = new WeakSet();

document.querySelectorAll('.item').forEach(el => {
  elements.add(el); // DOM 제거 시 자동으로 가비지 컬렉션됨
});

 

WeakMap/WeakSet

// 일반 Map/Set
const map = new Map();
const set = new Set();

let obj = { name: 'Kim' };

map.set(obj, 'value');
set.add(obj);

obj = null; // Map/Set에 참조가 남아있어서 메모리 해제 안 됨


// WeakMap/WeakSet
const weakMap = new WeakMap();
const weakSet = new WeakSet();

let obj = { name: 'Kim' };

weakMap.set(obj, 'value');
weakSet.add(obj);

obj = null; // 자동으로 WeakMap/WeakSet에서도 제거됨 (가비지 컬렉션)

 

핵심 차이점

특징 Map/Set WeakMap/WeakSet
키 타입 모든 타입 객체만
메모리 계속 유지 자동 해제
순회 가능 불가능
size 있음 없음

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함