메모리 관리 (Memory Management)
자바스크립트에서 성능과 안정성을 유지하려면 메모리 관리가 필수다. 메모리 누수가 생기면 애플리케이션이 느려지거나 멈출 수 있다. 이번에는 메모리 관리 방법을 기본부터 심화까지 코드와 함께 자세히 풀어보려고 한다.
메모리를 잘 관리하면 리소스를 효율적으로 사용하고, 장시간 실행되는 앱에서도 안정성을 유지할 수 있다. 하나씩 살펴보자.
기본적인 메모리 할당과 해제
자바스크립트는 자동으로 메모리를 관리하지만, 이해가 필요하다:
function createData() {
let bigArray = new Array(1000000).fill(0);
return bigArray;
}
let data = createData();
data = null; // 참조 제거로 가비지 컬렉션 유도
console.log("메모리 해제 준비 완료");
변수를 null
로 설정하면 참조가 끊어져 가비지 컬렉터가 메모리를 정리할 수 있다.
1. 메모리 누수 방지
전역 변수 사용을 줄이면 누수를 막을 수 있다:
// 잘못된 예
function leakMemory() {
window.globalData = new Array(1000000).fill("leak");
}
// 개선된 예
function safeMemory() {
const localData = new Array(1000000).fill("safe");
return localData;
}
safeMemory();
console.log("로컬 데이터로 메모리 관리");
전역 변수 대신 로컬 변수를 사용하니 함수 종료 후 메모리가 자연스럽게 해제됐다.
2. 이벤트 리스너 정리
사용하지 않는 리스너를 제거하면 메모리 누수가 줄어든다:
function setupListener() {
const button = document.querySelector("#btn");
const handler = () => console.log("클릭");
button.addEventListener("click", handler);
return () => button.removeEventListener("click", handler);
}
const cleanup = setupListener();
cleanup(); // 리스너 제거
console.log("리스너 정리 완료");
이벤트를 제거하니 DOM 요소와 관련된 메모리가 해제될 가능성이 높아졌다.
3. WeakMap으로 약한 참조 관리
WeakMap
을 사용하면 객체가 더 이상 필요 없을 때 자동으로 정리된다:
const cache = new WeakMap();
function storeData(obj) {
if (!cache.has(obj)) {
cache.set(obj, new Array(10000).fill(0));
}
return cache.get(obj);
}
let key = { id: 1 };
storeData(key);
key = null; // key 참조 제거
console.log("WeakMap으로 메모리 관리");
WeakMap
은 키 객체가 참조를 잃으면 자동으로 메모리에서 제거되니 관리가 편해졌다.
4. 클로저와 메모리 누수
클로저가 필요 이상으로 메모리를 잡아두지 않게 주의하자:
// 누수 발생
function leakyClosure() {
const largeData = new Array(1000000);
return () => largeData[0];
}
// 개선
function safeClosure() {
const largeData = new Array(1000000);
const result = largeData[0];
return () => result;
}
const fn = safeClosure();
console.log(fn());
필요한 데이터만 클로저에 저장하니 불필요한 메모리 점유가 줄었다.
5. 타이머 정리
타이머를 해제하지 않으면 메모리가 계속 쌓인다:
function startTimer() {
const id = setInterval(() => {
console.log("타이머 실행 중");
}, 1000);
return () => clearInterval(id);
}
const stop = startTimer();
setTimeout(stop, 5000);
console.log("타이머 정리 준비");
clearInterval
로 타이머를 정리하니 메모리 사용이 최적화됐다.
6. 대용량 데이터 처리
큰 데이터를 조각내서 처리하면 메모리 부담이 줄어든다:
function processLargeArray(arr) {
const chunkSize = 1000;
let index = 0;
function processChunk() {
const end = Math.min(index + chunkSize, arr.length);
for (; index < end; index++) {
arr[index] *= 2;
}
if (index < arr.length) {
setTimeout(processChunk, 0);
}
}
processChunk();
}
const largeArray = new Array(1000000).fill(1);
processLargeArray(largeArray);
데이터를 나눠 처리하니 한 번에 메모리를 많이 잡지 않았다.
7. 객체 재사용
새 객체 생성을 줄이고 기존 객체를 재사용하면 효율적이다:
// 비효율적
function createPoint(x, y) {
return { x, y };
}
// 효율적
const point = { x: 0, y: 0 };
function updatePoint(x, y) {
point.x = x;
point.y = y;
return point;
}
console.log(updatePoint(5, 10));
객체를 재사용하니 가비지 컬렉션 부담이 줄었다.
8. 메모리 프로파일링
도구를 활용해 메모리 사용을 분석할 수 있다:
function trackMemory() {
const data = new Array(1000000).fill("test");
console.log(performance.memory.usedJSHeapSize);
return data;
}
let result = trackMemory();
result = null;
console.log(performance.memory.usedJSHeapSize);
performance.memory
로 사용량을 확인하니 메모리 상태를 파악할 수 있었다 (Chrome에서만 동작).
9. 서비스 워커와 메모리
무거운 작업을 서비스 워커로 옮기면 메인 스레드 부담이 줄어든다:
// sw.js
self.onmessage = (e) => {
const result = new Array(1000000).fill(e.data);
self.postMessage(result);
};
// main.js
const worker = new Worker("sw.js");
worker.onmessage = (e) => console.log("작업 완료");
worker.postMessage(1);
별도 스레드에서 작업하니 메인 스레드 메모리가 덜 부담스러웠다.
10. 가비지 컬렉션 유도
의도적으로 참조를 끊어 메모리 해제를 돕자:
function forceCleanup() {
let temp = new Array(1000000).fill("temp");
temp = null;
if (globalThis.gc) globalThis.gc(); // Node.js에서 --expose-gc 옵션 필요
console.log("정리 완료");
}
forceCleanup();
참조를 제거하고 강제로 가비지 컬렉션을 유도하니 메모리가 즉시 정리됐다 (특정 환경에서만 가능).
마무리
메모리 관리는 성능과 안정성을 높이는 데 핵심적인 역할을 한다. 누수 방지, 약한 참조, 타이머 정리, 서비스 워커 활용까지 상황에 맞는 방법을 적용하면 효율적인 애플리케이션을 만들 수 있다.
'코딩 공부 > 자바스크립트' 카테고리의 다른 글
87. 자바스크립트 XSS 방어 (Preventing XSS) (2) | 2025.03.29 |
---|---|
86. 자바스크립트 렌더링 최적화 (Rendering Optimization) (2) | 2025.03.29 |
84. 자바스크립트 지연 로딩과 비동기 로딩 (Lazy Loading and Async Loading) (1) | 2025.03.28 |
83. 자바스크립트 캐싱 전략 (Caching Strategies) (2) | 2025.03.28 |
82. 자바스크립트 코드 최적화 기법 (Code Optimization Techniques) (1) | 2025.03.27 |