Javascript 메모리 누수가 발생하는 경우
자바스크립트에서 때때로 메모리 누수가 발생하는 경우가 있다.
가비지 컬렉터가 파악하지 못해 할당된 메모리가 해제되지 못할 수 있다.
이런 경우, 메모리 누수가 누적이 되면 성능저하와 심할경우 프로세스가 중단될 수도 있다.
메모리 누수가 발생하는 경우를 알고 이를 피하는 것이 좋은 자바스크립트 개발자이므로, 어떤 경우 메모리 누수가 발생하는지 알아보았다.
전역 변수의 사용
function fn() {
leak = "Global Variable Memory Leak";
}
위와 같은 전역 변수는 프로세스가 종료될 때 까지 메모리에 존재하므로, 사용하지 않는 전역 변수는 메모리 누수의 원인이 될 수 있다.
이벤트 리스너를 해제하지 않음
function EventListnerLeak() {
const btn = document.querySelector("#btn");
const clickHandler = () => {
console.log("clicked button...");
}
btn.addEventListener("click", clickHandler);
// btn.removeEventListener("click", clickHandler);
btn.remove();
}
요소가 사라진다 하여도 연결된 이벤트 리스너는 자동으로 없어지지 않는다.
요소를 해제하기 전 이벤트 리스너의 해제 과정도 필요하다.
타이머를 clear하지 않음
function timerLeak() {
const timer = setTimeout(() => {
console.log("Boom !");
// clearTimeout(timer);
}, 3000);
}
clear하지 않은 타이머 함수도 역시 메모리 누수의 원인이 될 수 있다.
사용하지 않는 객체의 참조
function createObject() {
const obj = { data: 'Some data' };
return obj;
}
function fn() {
const unusedObject = createObject();
// 사용하지 않는 객체를 참조하고 있음 -> 메모리 누수 발생
}
fn();
위에서 함수 fn이 호출되는데, 함수 내부에서는 다시 createObject 함수를 호출해 객체를 변수에 할당한다.
하지만, 이 변수는 할당된 뒤 사용되지 않고, 따라서 사용하지 않는 객체의 참조값을 가지고 있어 가비지 컬렉팅을 방해한다.
잘못된 클로저 함수 사용
function outerFunction() {
const externalArray = [1, 2, 3];
const innerFunction = () => {
return externalArray;
}
return innerFunction;
}
const closureFn = outerFunction();
closureFn 변수는 클로저인 innerFunction을 참조하고 있으므로, innerFunction은 계속해서 외부 배열 externalArray에 대한 참조를 유지하게 된다.
따라서 externalArray 배열은 더 이상 필요하지 않더라도 메모리에서 해제되지 않고 유지되고 메모리 누수의 원인이 된다.
순환 참조
let obj = {
name: "jane",
balance: 4500000,
};
const pointer = obj;
obj.circularRef = pointer;
obj = null;
console.log(pointer);
pointer는 obj를 참조한다.
그런데 obj의 circularRef 프로퍼티는 다시 pointer를 참조한다.
여기서 obj의 값을 null로 초기화해도, pointer가 obj를 가르키고, obj의 circularRef가 pointer(즉, obj)를 가르키는 자기참조가 발생하여 메모리 누수가 일어난다.