Home V8 엔진의 메모리 관리
Post
Cancel

V8 엔진의 메모리 관리

V8 메모리 관리

nodejs는 자바스크립트로 이루어져있고 자바스크립트는 V8엔진에 의해서 돌아간다

가비지 컬렉터의 작동하는 방식, 코드를 작성할 때 백그라운드에서 발생하는 일, 메모리가 해제되는 방식을 알아보자

메모리 영역

V8의 메모리공간을 Resident Set이라 부른다. 메모리 세그먼트는 아래와 같이 나뉜다

이미지

  • Code : 실행될 코드들
  • Stack : heap에 있는 object를 참조하는 포인터, 원시타입들이 있다.
  • Heap : object, string, 클로저와 같은 레퍼런스 타입을 저장한다.

  1. 새 영역(new space)
    • 새 할당이 발생하는 영역, 대부분의 객체들이 여기에 있다. 잦은 GC가 발생하기 때문에 빠르게 GC될수 있도록 설계되었다.
    • 메모리 크긴느 1~8MB 사이이며, Young Generation이라고도 부른다.
    • 20% 정도가 old space로 장기화된다.
  2. 오래된 영역(old space) : GC가 두 번 발생할 동안 “New 영역”에서 살아남은 객체들이 이동하는 영역
    • Old 포인터 영역: 살아남은 객체들을 가지며, 이 객체들은 다른 객체를 참조
    • Old 데이터 영역: Old 포인터에 가지 않은 살아남은 변수들. 문자열, 박싱(boxing)된 숫자, 실수형(double)로 언박싱(unboxing)된 배열
  3. 라지 오브젝트 영역(Large-object space)
    • 다른 space의 크기 제약보다 큰 크기를 가지는 객체들이 저장
    • 각 객체들은 고유의 memory-mapped 영역을 가지며, Garbage collector에 의해 수집되지 않는다
  4. 코드 영역 (Code space)
    • Just-In-Time 컴파일된 인스트럭션을 포함하는 코드 객체들이 저장된다.
    • 실행 가능한 메모리를 가지는 유일한 space이다.
  5. Cell space, Property-cell space, Map space
    • 각각 Cells, Property-Cells, Maps가 저장된다.
    • 이 공간들에 위치한 객체들은 모두 그 크기와 타입이 같아서 GC가 쉽다.

스택

V8 프로세스마다 하나의 스택을 가진다

메모리 관리

프로그램이 제대로 작동하려면 메모리가 필요하고 그 때문에 메모리 관리가 필요하다

응용프로그램 수준에서 메모리 관리는 자동/수동으로 나뉘는데 대부분의 프로그램들의 자동 메모리 관리는 가비지 콜렉터가 맡고 있다

수동으로 메모리를 관리는 C언어등에서 malloc, free 등을 통해 관리하는 것이다

수동 메모리 관리에서 주로 발생할 수 있는 버그들


  • 사용한 메모리 공간을 반환하지 않으면 메모리 누수가 발생한다
  • 개체된 객체의 포인터가 재사용되면 중요한 정보를 읽을 때 심각한 보안 문제가 발생할 수 있다

Node.js에는 가비지 수집기가 포함되어 있으므로 메모리 할당을 수동으로 관리할 필요가 없다

가비지 컬렉터의 개념


참조를 잃어 더이상 사용할 수 없는 객체들을 가비지 컬렉터가 자동으로 수집해서 메모리를 반환시켜준다

1
2
3
4
5
6
7
8
9
10
11
12
function Engine (power) {
  this.power = power
}

function Car (opts) {
  this.name = opts.name
  this.engine = new Engine(opts.power)
}

let LightningMcQueen = new Car({name: 'Lightning McQueen', power: 900})
let SallyCarrera = new Car({name: 'Sally Carrera', power: 500})
let Mater = new Car({name: 'Mater', power: 100})

이미지

Mater = undefined 코드를 추가하면 Mater 객체가 참조를 잃고 더이상 접근할 수 있는 방법이 없기 때문에 가비지 콜렉터에 의해 수집당한다

이미지

가비지 콜렉터

이미지

이런 모양을 가지고 있다

New Space : From-space, To-space

Old Space : Pointer Space, Data Space

  1. 대부분의 객체들은 그림 1번의 From-space에서 생성된다
  2. From-spaced에서 객체가 가득차면 To-space에서 가비지 콜렉터를 실행하고 살아남은 객체들을 그림 2번의 To-space로 옮긴다
  3. 1~2번의 과정으로 To-space마저 가득차면 To-space에서 가비지 콜렉터를 실행하고 객체를 그림 3번의 Old Space로 옮긴다
  4. Old Space까지 가득 찼다고 판단하면 V8은 메이저 가비지 콜렉터를 돌린다

메이저 가비지 콜렉터의 알고리즘은 다음과 같은 단계를 거친다

  1. 마킹

    현재 어떤 객체가 사용중인지 어떤 객체가 참조가 끊겨서 사용할 수 없는지를 판단한다 사용 중이거나 가능한 객체를 활성 상태로 마킹한다

  2. 스위핑

    가비지 콜렉터가 힙을 순회하면서 1단계에서 마킹하지 않은 객체들의 메모리 주소를 기록한다 이제 이 객체들의 메모리 주소에는 다른 객체들이 들어갈 수 있다

  3. 압축

    2단계가 끝난 후 모든 활성 객체들이 압축되어 메모리 공간의 효율을 높여 새 객체들의 할당 성능을 증가시킨다

메이저 GC는 앱을 잠시 멈추게하는데 이를 피하기 위해 다음과 같은 기술을 사용한다

  • 인크리멘탈 GC(Incremental GC): GC는 여러 개의 인크리멘탈 단계로 수행된다.
  • 동시 마킹(Concurrent marking): 마킹은 자바스크립트 메인 스레드에 영향을 주지 않고 다중 헬프 스레드를 사용해 동시에 수행된다. Write barrier는 헬퍼들이 동시에 마킹하는 동안 자바스크립트가 생성한 객체 간 참조를 추적하는 데 사용된다.
  • 동시 스위핑/압축(Concurrent sweeping/compacting): 스위핑과 압축은 자바스크립트 메인 스레드에 영향을 주지 않고 헬퍼 스레드에서 동시에 수행된다.
  • 레이지 스위핑(Lazy sweeping): 레이지 스위핑은 메모리가 필요할 때까지 페이지에서 가비지 삭제를 지연시킨다.
This post is licensed under CC BY 4.0 by the author.

하드웨어 가속

Redux