Node Garbage Collector란?

00_8_3·2021년 3월 26일
0

GC

C언어 같은 경우 메모리 관리를 위해 mallocfree를 사용한다.
반면 JS는 객체가 생성되었을 때 자동으로 메모리를 할당하고 쓸모 없어졌을 때 수동 또는 자동으로 해제해주는데
자동으로 메모리를 관리하는 경우를 Garbage Collector, GC라고 합니다.

참조

GC 알고리즘의 핵심 개념으로 A라는 메모리를 통해 B라는 메모리에 접근할 수 있으면 B는 A에 참조된다라고 합니다.

참조-세기 GC

참조 세기 알고리즘더 이상 필요 없는 객체어떤 객체도 참조하지 않는 객체로 정의하고 이러한 객체를 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를 수행한다.
이러한 알고리즘이 순환참조의 문제를 해결하기 하였습니다.

GC Methods

New space, Old space

HeapNew space, Old space 두개의 메인 영역을 갖습니다.
New space는 새로운 할당이 일어나는 곳 입니다. GC가 자주 일어나고 1~8MB의 사이즈를 갖습니다. 이곳에 존재하는 객체를 Young Generation이라고 합니다.

Old spaceNew space에서 GC로 부터 살아남은 객체들이 이동합니다. Old space에 존재하는 객체를 Old Generation이라고 하고 Old space는 할당은 빠르지만 GC비용이 비싸기 때문에 자주 수행 되지 않습니다.

Young generation

일반적으로 약 20% Young generation이 살아남아 Old Generation이 됩니다.
Old space에서는 가용 메모리가 다 소진되면 GC가 수행됩니다.

Scavenge and Mark-sweep

ScavengeYoung generation에서 수행되며 수집이 빠릅니다.

Mark-sweepOld generation에서 수행되며 상대적으로 느립니다.

메모리 누수의 원인

Mark-sweep으로 인해 순환참조로 인한 메모리 누수는 사라졌지만 아래와 같은 대표적 원인들이 있습니다.

  • 1 전역변수
  • 2 다중참조
  • 3 클로저
  • 4 콜백함수

메모리 누수 피하기

  • 1 전역변수 최소화하기

    1 가능하면 지역변수로 선언
    2 불가피하면 그 수와 용량을 최소화
    3 전역변수를 다 사용했으면 null이나 undefined로 바꿔 GC의 대상이 되게 한다.

  • 2 힙 데이터를 스택으로 끌어내리기
    메모리 구조상 보다 스택이 훨 씬 빠릅니다.
    비구조화 할당 문법을 사용해 객체의 각 필드를 스택 메모리로 끌어 내리면 성능이 좋아집니다.

Ex 1)

const User = req.user
// 위를 아래처럼 바꾼다.
const {user} = req
  • 3 다중참조를 막기위해 객체 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모드를 사용하면 됩니다.

0개의 댓글