C 언어에서는 메모리 관리를 위해 malloc 과 free 를 이용해 할당하고, 해제하는 것을 개발자가 명시적으로 사용해줘야했다.
하지만 자바스크립트는 객체가 생성되었을 때 자동으로 메모리를 할당하고 더 이상 필요하지 않을 때 자동으로 해제한다.
(사실 거의 대부분의 고수준 언어들이 암묵적으로 동작한다.) 많이 들어봤던 가비지 컬렉션에 대한 내용이다.
자바스크립트 메모리 할당
1. 값 초기화
자바스크립트는 값을 선언할 때 자동으로 메모리를 할당한다.
2. 함수 호출을 통한 할당
let date_time = new Date()
위와 같이 함수 호출의 결과 메모리 할당이 일어나기도 한다.
메소드가 새로운 값이나 오브젝트를 할당하는 경우도 있다.
자바스크립트 메모리 해제
C는 개발자가 더이상 메모리가 필요없을 때 free 를 통해 직접 제어해서 결정할 수 있었다.
그런데, JS 는 어떻게 "할당된 메모리가 더 이상 필요없을 때"를 알아낼 수 있을까?
가비지 콜렉션이라는 자동 메모리 관리 방법이 있다.
가비지 콜렉터가 메모리 할당을 추적하고 이 메모리가 더 이상 필요하지 않게 되었는가? 를 판단하여 할당된 메모리를 회수한다.
MDN 문서에 따르면 이러한 자동 메모리 관리 프로세스가 궁극의 방법은 아니라고 한다. (필요/불필요의 판단 문제는 비결정적 문제이기 때문에)
가비지 콜렉션에 대해 좀 더 깊게 알아보자.
가비지 콜렉션
참조
가비지 콜렉션 알고리즘의 핵심 개념은 참조이다.
Reference-counting 가비지 콜렉션
가장 단순하게 구현된 알고리즘으로,
어떤 다른 오브젝트도 참조하지 않는 오브젝트를 "더 이상 필요 없는 오브젝트" 라고 여긴다.
이 오브젝트를 "가비지" 라 칭하며, 이를 참조하는 다른 오브젝트가 하나도 없는 경우 수집이 가능해진다.
let x = {
a: {
b: 2
}
}
// 2개의 오브젝트가 생성되었고, 하나의 오브젝트는 다른 오브젝트의 속성으로 참조 된다.
// 나머지 하나는 'x' 변수에 할당되었다.
// 가비지 콜렉션 수행될 메모리는 하나도 없다.
let y = x; // y 변수는 위의 오브젝트를 참조하는 두번째 변수이다.
x = 1; // y 변수가 위의 오브젝트를 참조하는 유일한 변수가 되었다!
let z = y.a; // 위 오브젝트의 'a' 속성을 참조했다.
// 이제 'y.a'는 두 개의 참조를 가진다.
// 'y'가 속성으로 참조하고 'z'라는 변수가 참조한다.
y = 'mozilla'; // 참조하는 유일한 변수였던 y 에 다른 값을 대입했다.
// 오브젝트의 'a' 속성이 여전히 'z'변수에 의해 참조되므로 메모리 해제 불가능
z = null; // 'z' 변수에 다른 값을 할당했다.
// 드디어 가비지 콜렉션이 수행된다.
순환 참조는 한계가 명확하다.
아래 예제를 확인해보자.
function f() {
var x = {};
var y = {};
x.a = y; // x는 y를 참조합니다.
y.a = x; // y는 x를 참조합니다.
return "azerty";
}
f();
두 객체가 서로 참조하는 속성으로 생성되어 순환 구조를 생성한다.
함수 호출이 완료되면 이 두 객체는 스코프를 벗어나며,
이 시점에서 두 객체는 필요하지 않으므로 할당된 메모리는 회수되어야 마땅하다.
하지만 두 객체가 서로를 참조하고 있기때문에
두 객체 다 가비지 컬렉션의 대상으로 표시하지 않는다.
이게 곧... 메모리 누수로 이어진다!
Mark-and-sweep 알고리즘
자바스크립트에서 root 는 전역 오브젝트이다.
주기적으로 가비지 콜렉터는 roots 에서 시작해서 roots 가 참조하는 오브젝트들,
roots가 참조하는 오브젝트가 참조하는 오브젝트.. 등을 찾는다.
이 알고리즘은 reference-counting 보다 개선된 형태라고 할 수 있다.
바로 위의 예시에서 함수 호출이 리턴되고 나서 두 객체들은
더이상 전역 객체에서 참조하고 있는 어떤 리소스에서도 참조하지 않는다.
결국 두 객체들은 가비지 컬렉터가 닿을 수 없는 것으로 판명되고 할당되었던 메모리를 회수하게 되는 것이다.
현재 모든 최신 엔진은 이 가비지 콜렉션을 제공한다.
엔진의 메모리 모델 설정하기
가용 힙 메모리의 최대량은 아래와 같이 설정할 수 있다.
node --max-old-space-size=6000 index.js
메모리 관리를 돕는 데이터 구조
자바스크립트는 가비지 컬렉터 API 를 직접적으로 노출하지는 않고,
간접적으로 관리할 수 있는 몇 개의 데이터 구조를 제공한다.
바로 WeakMap 과 WeakSet 이다.
출처 : https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_management
'Programming > JavaScript' 카테고리의 다른 글
ENOSPC ERROR 해결 (0) | 2022.12.13 |
---|---|
[ 모던 자바스크립트 스터디 ] Ajax (0) | 2022.11.06 |
[ 모던 자바스크립트 스터디 ] REST API (0) | 2022.11.05 |
[ 모던 자바스크립트 스터디 ] 비동기 프로그래밍 (0) | 2022.11.05 |
[ 모던 자바스크립트 스터디 ] 타이머 (0) | 2022.11.05 |