가비지 컬렉션을 번역해보면 쓰레기 모음집이다! 이는 더이상 사용되어지지 않는 메모리인데 아직은 방출되지 않은 메모리를 의미한다. 그러면 여기서 사용은 무엇이고, 방출은 무엇일까? 해당 내용을 살펴보면 다음과 같다!
메모리의 lifecycle은 Allocate memory
-> Use memory
-> Release memory
의 3단계의 라이프 사이클을 가진다. 메모리가 저장되고, 사용되어진다. 그 후에 끝나게 되면 방출이 되어진다.
즉, 정리하자면 가비지 컬렉션은 메모리가 사용되면 방출되어져야 하는 데 이 과정이 이뤄나지 않은 것들을 모은 것을 의미한다.
C언어 에서는 명시적으로 메모리를 할당 해제 하지만 JS에서는 수동으로 메모리를 관리하는 대신 가비지 컬렉션이 알아서 메모리를 관리해준다. 메모리에 할당된 값이 더이상 필요하지 않다고 판단될 때 메모리를 해제시키는 과정을 가비지 컬렉션이라고 부르며 이 역할을 가비지 컬렉터가 맡고 있다.
가비지 컬렉터가 ‘필요없다’라고 판단하는 기준은 더 이상 '객체에 닿을 수 없을 때'를 말한다. 닿는다는 roots(전역 변수)를 기준으로 참조, 또는 참조의 참조의… 참조가 되는 객체들입니다. 이 알고리즘을 mark and sweep이라고 부르는데 가비지 컬렉터는 ‘root에서 닿을 수 있는’ 객체들의 reachable을 true로 표시하고, false인 객체들은 메모리에서 해제시킨다.
이는 클로저를 사용될 때 필요없어지면 해제가 되지 않는 문제점이 발생하게 되어진다. 즉, 가비지 컬렉터가 일어나지 않게 된다!
하지만 클로저를 통해서 템플릿처럼 사용한다면 메모리 누수 문제가 일어나게 된다.
가비지 컬렉터는 알아서 메모리 관리를 해준다는 장점이 있지만, 반대로 수동으로 메모리 해제를 할 수 없기 때문에 발생하는 메모리 누수 문제가 있다. Closure는 Mark And Sweep 알고리즘을 이용해 실행이 끝난 함수의 Lexical Environment를 메모리에서 해제하지 않고 유지한다. 즉, Closure의 필요성을 마친 뒤에도 ‘필요없음’을 가비지 컬렉터에게 알리지 않는다면 메모리 누수가 발생하게 되는 것이다!
closure에서 해당 된 변수가 사용되어지고 이를 메모리에서 지우는 방법은 간단하다! Closure를 담고있는 객체를 다른 값으로 초기화 시키면 더 이상 root에서 참조되지 않는 Closure를 가비지 컬렉터가 메모리 해제하게된다!
function makeClosureFunc(hi) {
const name = "peter";
return function () {
console.log(`${hi} ${name}~!`);
};
}
const sayHiToPeter = makeClosureFunc("Good morning!");
sayHiToPeter(); //Good morning! peter~!
// ~ 함수의 필요성이 완료됨 ~
sayHiToPeter = null;
// 가비지 컬렉터가 이전 할당 값인 Closure의 reachable이 false 된 것을 확인하고 메모리에서 해제 함
이렇게 closure의 메모리 누수 문제 때문에 클로저의 사용을 자제해야한다는 의견도 있다고 한다. 이러한 클로저를 대체하기 위해서는 즉시 실행함수를 이용하여 private data를 구현하는 방법도 있다!
(function makePrivateFunc() {
const message = "private data";
const privateFunc = function () {
console.log(`${message} can also implemented through the IIFE`);
};
privateFunc();
})();
출처) https://blog.sessionstack.com/how-javascript-works-memory-management-how-to-handle-4-common-memory-leaks-3f28b94cfbec
https://dkje.github.io/2020/09/18/Closure/