https://ykss.netlify.app/translation/javascript_memory_management/?utm_source=oneoneone 를 읽고 정리
자바스크립트 엔진은 어떻게 메모리를 관리하나요?
자바스크립트 엔진은 가비지 컬렉터를 사용해 더이상 사용하지 않는 메모리를 확보한다.
가비지 컬렉터는 애플리케이션에서 더이상 사용하지 않는 객체를 찾아내고 제거한다.
가비지 컬렉터는 코드의 객체와 변수를 지속적으로 모니터링하고 어떤 객체가 참조되고 있는지 추적하기 때문에 가능하다.
흔한 메모리 누수의 원인은 무엇인가요?
1. 순환참조
두개이상의 객체가 서로를 참조하여 가비지 컬렉터가 끊을 수 없는 순환을 생성할 때 메모리 누수가 발생한다.
객체가 언제 사용되지 않는지 판단할 수 없기 때문에, 계속 메모리를 차지하게 된다.
let object1 = {};
let object2 = {};
// 객체1과 객체2 사이에 순환 참조를 생성합니다.
object1.next = object2;
object2.prev = object1;
// object1과 object2로 무언가를 수행합니다.
// ...
// 순환 참조를 끊으려면 object1과 object2를 null로 설정합니다.
object1 = null;
object2 = null;
이러한 유형의 메모리 누수를 방지하려면, delete 키워드로 순환 참조를 생성하는 프로퍼티를 제거하는 수동 메모리 관리 기술을 써야 한다.
delete object1.next;
delete object2.prev;
혹은, 약한 참조를 생성해낼 수 있는 WeakMap WeakSet 을 사용한다.
2. 이벤트 리스너
이벤트 리스너를 요소에 연결하면 리스너 함수에 대한 참조가 생성된다. 요소가 더 이상 필요하지 않을 때 리스너 함수를 제거하지 않으면 계속 참조된다.
+ https://yzlosmik.tistory.com/107 에 정리한 내용처럼, 함수는 힙메모리에 해당 함수의 참조값이 저장하게 되는데, 이벤트리스너를 익명함수로 연결하게 되면 매번 새로운 참조값을 지니는 함수가 힙메모리에 저장된다.
let button = document.getElementById('my-button');
// 버튼 요소에 이벤트 리스너를 붙입니다.
button.addEventListener('click', function() {
console.log('Button was clicked!');
});
// 버튼이 무언가 동작을 합니다.
// ...
// DOM에서 버튼을 제거합니다.
button.parentNode.removeChild(button);
버튼요소는 없지만 이벤트 리스너는 여전히 연결되어 있으므로, 리스너 함수에 대한 참조가 생성되어 가비지 컬렉터가 메모리 확보하지 못한다.
요소가 더이상 필요하지 않을 때 이벤트 리스너를 제거하는 것이 중요하다.
button.removeEventListener('click', function() {
console.log('Button was clicked!');
});
button.removeAllListeners();
3. 전역변수
전역변수를 생성하면 코드 어느 위치에서나 접근할 수 있어서 더이상 필요하지 않는 시점을 판단하기 어렵다.
// 전역 변수를 선언합니다.
let myData = {
largeArray: new Array(1000000).fill('some data'),
id: 1,
};
// myData 변수로 무언가를 수행합니다.
// ...
// 참조를 끊기 위해 myData를 null로 설정합니다.
myData = null;
참조를 끊기 위해 myData를 null 로 설정했지만, 변수가 전역이라 코드의 어느 위치에서나 여전히 접근이 가능하다.
이러한 유형은 함수 스코핑 기법으로 메모리 누수를 방지할 수 있다.
함수를 생성해서 해당 함수내에 변수를 선언하여 해당 함수의 스코프 내에서만 접근할 수 있다.
이렇게 되면, 함수가 더이상 필요하지 않을 때 변수가 자동으로 가비지 컬렉팅이 된다.
요소에 이벤트리스너를 단 후 요소가 제거되었다고 해서, 요소에 대한 이벤트리스너의 메모리도 확보되는 것은 아니다.
여전히 요소에 대한 참조가 메모리에 저장되어있기 때문에, 요소가 제거되기 전에 꼭 이벤트 리스너를 제거해주자.
'🌳Frontend > etc' 카테고리의 다른 글
Styled Components Naming Convention (1) | 2023.04.13 |
---|---|
자바스크립트의 참조에 의한 객체 복사 (0) | 2023.04.13 |
익명함수의 메모리 누수 (0) | 2023.04.10 |
[JS 문제] Array Sort Comparison / 배열의 동등비교 (0) | 2023.03.26 |
프론트엔드 개발자라면 알아야할 : Webpack 심화 (0) | 2023.03.24 |