C언어 같은 경우 메모리 관리를 위해 malloc
과 free
를 사용한다.
반면 JS는 객체가 생성되었을 때 자동으로 메모리를 할당하고 쓸모 없어졌을 때 수동 또는 자동으로 해제해주는데
자동으로 메모리를 관리하는 경우를 Garbage Collector
, GC라고 합니다.
GC 알고리즘의 핵심 개념으로 A라는 메모리를 통해 B라는 메모리에 접근할 수 있으면 B는 A에 참조된다
라고 합니다.
참조 세기 알고리즘
은 더 이상 필요 없는 객체
를 어떤 객체도 참조하지 않는 객체
로 정의하고 이러한 객체를 Garbage
로 부르고 수집을 합니다.
function f(){
var o = {};
var o2 = {};
o.a = o2; // o는 o2를 참조한다.
o2.a = o; // o2는 o를 참조한다.
return "azerty";
}
f();
두 객체가 서로를 순환 참조를 하는 구조를 생성하여 참조-세기 알고리즘
의 GC 대상으로 표시되지 않아 메모리 누수
의 원인이 됩니다.
Mark and sweep
이 알고리즘은 roots
라는 객체의 집합을 가지고 있어서
주기적으로 GC는 roots
로 부터 시작하여 roots가 참조하는 객체들
, roots가 참조하는 객체가 참조하는 객체들
... 을 닿을 수 있는 객체
라고 표시합니다.
그리고 닿을 수 있는 객체
가 아닌 닿을 수 없는 오브젝트에 대해 GC
를 수행한다.
이러한 알고리즘이 순환참조의 문제를 해결하기 하였습니다.
Heap
은 New space
, Old space
두개의 메인 영역을 갖습니다.
New space
는 새로운 할당이 일어나는 곳 입니다. GC
가 자주 일어나고 1~8MB
의 사이즈를 갖습니다. 이곳에 존재하는 객체를 Young Generation
이라고 합니다.
Old space
는 New space
에서 GC
로 부터 살아남은 객체들이 이동합니다. Old space
에 존재하는 객체를 Old Generation
이라고 하고 Old space
는 할당은 빠르지만 GC
비용이 비싸기 때문에 자주 수행 되지 않습니다.
일반적으로 약 20%
Young generation
이 살아남아 Old Generation
이 됩니다.
Old space
에서는 가용 메모리가 다 소진되면 GC
가 수행됩니다.
Scavenge
는 Young generation
에서 수행되며 수집이 빠릅니다.
Mark-sweep
은 Old generation
에서 수행되며 상대적으로 느립니다.
Mark-sweep
으로 인해 순환참조
로 인한 메모리 누수는 사라졌지만 아래와 같은 대표적 원인들이 있습니다.
1 전역변수 최소화하기
1 가능하면 지역변수로 선언
2 불가피하면 그 수와 용량을 최소화
3 전역변수를 다 사용했으면null
이나undefined
로 바꿔 GC의 대상이 되게 한다.
2 힙 데이터를 스택으로 끌어내리기
메모리 구조상 힙
보다 스택
이 훨 씬 빠릅니다.
비구조화 할당
문법을 사용해 객체의 각 필드를 스택
메모리로 끌어 내리면 성능이 좋아집니다.
Ex 1)
const User = req.user
// 위를 아래처럼 바꾼다.
const {user} = req
객체 Spread
또는 Object.assign()
을 사용해 복사본을 생성하고 객체의 참조를 넘겨서 같은 객체의 다중참조 가능성
을 낮춰야 합니다.Ex 2)
// Object Spread
const a = {
x : 0 ,
y : 0
};
const b = { ...a };
b.x++;
console.log(a); // x:0, y:0
console.log(b); // x:1, y:0
Ex 3)
// Object.assign(holder, data);
// data의 데이터를 holder로 옮깁니다.
// 해당 함수의 리턴값은 holder의 참조값입니다.
const a = {
x : 0 ,
y : 0
};
const holder = { };
const b = Object.assign(holder, a);
a.x++;
console.log(a); // x:0, y:0
console.log(b); // x:1, y:0
console.log(holder); // x:1, y:0
Node
는 기본 inspector
또는 heapdump 모듈
을 사용하고
Nest
는 스크립트에 제공되는 start:debug
모드를 사용하면 됩니다.