V8 엔진
: Google이 개발한 C++ 기반의 오픈소스 엔진
: NodeJS 런타임 및 크롬 브라우저에서 사용
: JavaScript에서 사용
v8 엔진을 사용하는 이유
: 웹 특성상 동적 인터프리터 방식을 많이 사용하기 때문에 기존 자바스크립트 엔진으로는 속도가 느려짐
: v8은 JIT 컴파일러를 적용하여 JS 코드를 효율적으로 기계어 코드로 번역
※ JIT
: 실행시점에 인터프리트 방식으로 기계어 코드를 생성하면서 코드를 캐싱하는 컴파일 기법
: 컴파일을 할 때 필요한 자원을 실행시간에 공유
=> v8은 바이트코드와 중간코드를 생성하지 않음
v8 엔진의 메모리 구조
```
rss: {
heap: { ... }
stack: { ... }
}
```
RSS (Resident Set)
: V8 프로세스에서 할당된 일정량의 메모리
: JS로 작성한 프로그램에 할당된 전체 메모리
힙 메모리
: 객체나 동적 데이터를 저장
: 메모리 블록에서 가장 큰 영역이면서 가비지 컬렉션이 발생하는 곳
: 가비지 컬렉션은 New 영역과 Old 영역에서 실행
New 영역
: 새로 만들어진 객체를 저장하는 영역
: 2개의 세미 영역을 가짐 (마이너 GC가 관리)
: --min_semi_size (초기값)과 --max_semi_space_size (최대값)을 조정 가능
Old 영역
: New 영역의 세미 영역에서 마이너 GC가 두 번 발생할 동안 New 영역에서 살아남은 객체들이 이동하는 영역
: 메이저 GC에 의해 관리
: --initial_old_space_size (초기값)과 --max_old_space_size (최대값)을 통해 조정 가능
- old 포인터 영역
: 살아남은 객체들을 가지며, 이 객체들은 다른 객체를 참조
- old 데이터 영역
: 다른 객체를 참조하지 않고 데이터만 가진 객체들을 가짐
: 문자열, 박싱된 숫자, 실수형으로 언박싱된 배열이 New 영역에서 여기로 이동
라지 오브젝트 영역
: 다른 영역의 제한된 크기보다 큰 객체들이 있는 영역
: 이 영역의 객체들은 GC에 의해 처리되지 않음
코드영역
: 컴파일된 코드을 저장하는 영역
: 실행 가능한 메모리가 있는 영역으로 라지오브젝트에 할당 될 수 있도 실행도 가능한 영역
셀영역 / 속성 셀 영역 / 맵 영역
: Cells, PropertyCells, Maps를 포함
※ 각 영역은 페이지들로 구성되어 있고, 페이지는 운영체제에서 mmap 또는 MapViewOfFile로 할당된 연속된 메모리 청크를 의미
: 각 페이지 크기는 라지오브 프로젝트 영역을 제외하고 1MB를차지
스택 메모리
: 운영체제에 의해 자동으로 관리
: v8 프로세스 마다 하나의 스택을 가짐
: 메서드와 함수 프레임, 원시 값, 객체 포인터를 포함한 정적 데이터가 저장 됨
: --stack_size 를 통해 설정 가능
메모리 관리에 대해서
: 힙은 가장 큰 메모리 영역과 동적 데이터를 보유함
: 프로그램이 사용가능한 것 보다 더 많은 메모리를 힙에 할당하려고 할때 메모리 부족 오류가 발생함
스택에 저장되는 데이터
- 전역 스코프
: 전역 프레임에 저장
- 모든 함수 호출 (프레임 블록)
: 함수자 종료되면 스택에서 제거됨
- 반환 값과 인자를 포함한 모든 지역 변수
: 프레임 블록에 저장
- Int 및 String과 같은 원시 타입 값
: 스택에 직접 저장
: 전역 스코프에서도 적용되며 JS에서 문자열은 문자 타입에 해당
- Employee와 Function과 같은 객체 타입
: 힙에서 생성되고 스택 포인터를 통해 힙에서 스택을 참조
: 전역 스코프에서도 적용
- 현재 함수에서 호출된 함수
: 스택의 최상단에 추가
※ 주요 프로세스가 완료될 때 힙에 있는 객체들은 어떤 포인터도 가지고 있지 않고 혼자 남게 됨
※ 명시적으로 복사하지 않으면, 다른 객체 내의 모든 객체 참조들은 참조 포인터를 사용해 연결 됨
※ 명시적 복사 (Deep Copy)
: 실제 값을 복사하는 것
: 값을 복사하면서 다른 독립적인 메모리 공간에 할당
※ 얕은 복사 (Shllow Copy)
: 같은 참조를 복사 하는 것
: 객체를 복사할 때 기존 값과 복사된 값이 같은 참조를 가리키는 경우
: 객체안에 객체가 있는 경우 한 개의 객체라도 기존 변수의 객체를 참조한다면 얕은 복사
V8 엔진의 힙 메모리 관리
: 힙은 V8 엔진에 의해서 관리됨
- 태그된 포인터 (Tagged Pointer)
: V8 엔진에서 포인터와 데이터를 구분하기 위한 접근 방식
: 각 단어의 끝에 포인터 또는 데이터인지 나타내는 비트 값을 저장
: 제한적인 컴파일러 지원이 필요하지만 효율적이면서 구현하기 쉬움
가비지 컬렉션
: 참조가 없는 객체들이 사용하는 메모리를 비워 새로운 객체를 생성하기 위한 공간을 확보
- 참조가 없는 객체 (Orphan Object)
: 스택 (다른 객체 내부의 참조)으로 부터 더 이상 직간접적으로 참조되지 않는 객체
- Orinoco
: 가비지 컬렉션에 병렬, 인크리멘탈 및 동시 기술을 사용하여
메인 스레드를 방해하지 않도록 하는 V8 GC 프로젝트의 코드명
마이너 GC (Scavenger)
: New 영역 (Young 제너레이션)을 정리하는 과정
: 새로 생성된 객체들은 New 영역에 1~8MB 크기로 할당되는데, 새 객체에 대한 공간을 예약하려고 할 때마다
증가하는 할당 포인터가 있어 비용이 저렴함
: 할당 포인터가 New 영역의 마지막에 도달할때 마이너 GC가 발생하는데 이 과정을 스캐벤져 라고함
: Cherry의 알고리즘을 사용해 구현됨
: 매우 자주 발생되며 병렬 헬퍼 스레드를 사용하며, 굉장이 빠름
- To 영역
: New 영역의 세미영역
: 대부분의 할당이 이루어지는 영역
: To 영역이 가득찰 경우 마이너 GC가 발생됨
- From 영역
: 마이너 GC가 발생했을 때 To 영역의 데이터들을 보관하는 영역
: 여기에 있는 데이터들은 가비지로 취급되어 삭제됨
메이저 GC
: Old 제너레이션 영역을 정리하는 기능
: V8에서 Old 영역의 메모리가 충분하지 않다고 판단될 때 발생
: Old 영역은 동적으로 계산된 크기에 기반하며 마이너 GC 주기에서 채워짐
: 메모리 오버헤드가 있기 때문에 메이저 GC는 Mark-Sweep-Comact 알고리즘을 사용하여 처리됨
: 메이저 GC는 Tri-Color 마킹 시스템을 사용
- 마킹
: 가비지 컬렉터가 어떤 객체가 사용중인지 식별하는 단계
- 스위핑
: 가비지 컬렉터가 힙 메모리를 순회하면서 활성 상태로 표시되지 않은 객체들의 메모리 주소를 기록
- 압축
: 조각화를 줄이고 새 객체들에 대한 메모리 할당 성능을 증가 시키는 단계
Refference
'Programming > NodeJS' 카테고리의 다른 글
NodeJS에서 로깅하기 (0) | 2022.08.13 |
---|---|
NodeJS의 메모리 누수 확인 방법 (0) | 2022.08.13 |
NodeJS 순환 참조 문제 해결 방법 (typeerror: converting circular structure to json) (0) | 2022.08.01 |
NodeJS rest-client API JSON이 undefined로 나올때 (0) | 2022.07.30 |
vscode 이 시스템에서 스크립트를 실행할 수 없으므로 오류 해결법 (0) | 2022.07.30 |