자바스크립트 엔진
: 사람이 작성한 자바스크립트 파일을 컴퓨터가 읽을 수 있도록 최적화된 코드로 변환하는 역할 수행
: 자바스크립트 코드를 마이크로 프로세서가 이해할 수 있는 기계어로 변환하는 프로그램 혹은 인터프리터
: 웹 사이트의 경우 브라우저의 자바스크립트 엔진을 사용
- 자바스크립트 엔진의 종류
: Rhino (모질라)
: SpiderMoney (파이어폭스)
: V8 (구글, 오페라)
: JavaScriptCore (사파리)
: Chakra (익스플로러, 엣지)
※ 인터프리터
: 코드를 한 줄 씩 기계어로 번역하는 코드 실행 방식
: 컴파일 단계가 없어 실행 속도가 빠름
※ 컴파일러
: 코드 전체를 읽고 컴파일이라는 과정을 거쳐 기계어로 번역하는 코드 실행 방식
: 불필요한 동작을 제거하는 최적화 (Optimization)을 거쳐 작업을 단순화 시킴
V8 엔진
: 웹 브라우저 내부에서 자바스크립트의 수행 속도를 개선하기 위해 개발된 엔진
- 다른 자바스크립트 엔진
: 유저와 상호작용을 위해 인터프리터를 사용
: 이 경우 코드가 많아질 수 록 실행 속도가 느려진다는 단점 존재
- JIT (Just In Time)
: V8에서 사용하는 컴파일러 방식
: 코드를 실행할 때 기계어로 컴파일
: 코드의 반복 빈도가 높아질때 만들어놓은 기계어를 재사용할 수 있다는 장점 존재
: 자주 반복되는 코드가 없는 경우 수행시간이 길어질 수 있음
- JITC (Just In Time Compliation) / 동적 번역 (dynamic translation)
: 프로그램을 실행하는 시점에 기계어로 번역하는 컴파일 기법
: Just In Time 컴파일러로 프로파일링을 통해 최적화할 코드를 선별한 후 해당 코드들만 컴파일 수행
: 컴파일레이션을 통해 번역된 바이트코드를 VM상에서 실행
V8의 작동 방식
- Tokenizer
: 자바스크립트 코드를 분석하여 의미를 갖는 최소 단위인 토큰으로 분해
: 낱말 분석 (Lixcal Analysis)라는 과정을 거침
- Parser
: Parser에서 분해된 토큰을 바탕으로 AST tree를 생성
: 토큰 (parse tree)를 필수적인 정보만 담은 트리로 변경
- Ignition
: AST tree 구조의 코드를 바이트코드로 중간 번역하는 인터프리터
※ Bytecode
: 가상머신이 이해할 수 있도록 하는 이진 코드
: V8 엔진이 읽기에 최적화된 코드
- Compiler TurboFan (JIT Compiler)
: V8 엔진에 대해 최적화된 이진코드를 CPU에게 최적화된 기계어로 컴파일하여 코드를 실행
: Profiler가 코드의 최적화가 가능한 부분을 찾으면 이를 컴파일러에게 전달 하고,
컴파일러는 인터프리터로 인해 웹 사이트가 구동되는 동안 필요한 부분을 기계어로 변환하여 최적화를 진행
- Optimized Code
: 최적화 코드를 수행할 차례가 되면 바이트코드 대신 컴파일러가 변환한 최적화된 코드가 대체되어 실행됨
: Hidden class 혹은 Inline caching 기법을 사용하여 최적화
※ Hidden class
: 비슷한 코드끼리 분류해놓고 가져다 쓰는 기법
: 고정된 클래스와 고유 주소를 사용하여 위치를 찾아 실행
: 런타임 도중, 객체 구조의 동적인 변화가 수행될 때 마다 수행
※ Inline caching
: 자주 사용하는 코드를 보관해놓고 사용
: 특정 함수의 호출부가 자주 사용된다면 해당 호출부를 function으로 변환
단일스레드
: 각 자바스크립트 실행 컨텍스트는 하나의 스레드를 가짐
: V8은 각 자바스크립트 컨텍스트 마다 하나의 싱글 스레드 환경을 만듦
: 각 함수를 삽입 혹은 호출한 순서에 따라 스택 방식으로 동작
※ 실행 컨텍스트
: 실행할 코드에 제공할 환경 정보들을 모아놓은 객체
V8 엔진의 컴파일러
- 풀코드젠 (Full Codegen)
: 최적화 되지 않은 코드를 생성해주는 빠른 컴파일러
: 바이트코드 없이 기계어로 컴파일 수행
- 크랭크 샤프트 (Crankshaft)
: 빠르고 최적화된 코드를 생성하는 느린 컴파일러
: 풀코드젠이 생성한 코드를 크랭크 샤프트가 검사하여 코드를 변경
: AST를 고수준 정적단일 할당 (SSA)로 번역하는데 이를 하이드로젠이라고 부름
V8 엔진의 구조
: Heap memory와 Stack memory로 구성
: 스택은 컴파일 타임에 크기가 결정됨
: 힙은 런타임에 크기가 결정됨
- Stack memory
: 함수 호출과 관계되는 지역변수와 매개변수가 저장됨 (원시값)
> 지역 변수중 참조 타입은 스택에 주소 값만 저장되고 값은 힙에 저장 됨
: 스택에 저장된 값은 함수의 호출과 함께 할당되며 함수의 호출이 완료되면 소멸됨
: LIFO 방식으로 작동
- Heap memory
: 사용자에 의해 직접 관리할 수 있는 메모리 영역
: 전역 변수와 객체가 저장되며, 참조 정보는 스택에 저장됨
: 할당 해제를 제대로 하지 않을 경우 memory leak이 발생
: V8 엔진에서는 여러 영역으로 나누어 관리됨
V8 엔진에서의 힙 메모리 구조
- New space
: 대부분의 오브젝트가 할당되는 장소
: 1~8MB의 크기를 가지고 다른 space와 독립적으로 가비지 컬렉션이 발생
- Old pointer space
: 다른 객체에 대한 포인터를 가진 객체가 저장되는 장소
: 다른 유효한 객체에서 사용중인 이유로 New space에서 삭제되지 않은 객체들이 저장됨
- Old data space
: Raw data를 가진 객체가 저장되는 장소
: strings, boxed numbers, unboxed double의 배열 등을 저장
: 다른 유효한 객체에서 사용중인 이유로 New space에서 삭제되지 않은 객체들이 저장됨
- Large object space
: 다른 space의 크기 제약보다 큰 크기를 가지는 객체들을 저장
: 개별 객체는 고유의 memory mapped 영역을 가지며 가비지 컬렉터에 의해 수집되지 않음
- Code space
: Just In time 컴파일된 코드 객체가 저장되는 장소
: 실행가능한 메모리를 가진 유일한 space
- Cell space / Property cell space / Map space
: Cells, Property cells, Maps가 저장되는 장소들
: 이 공간에 위치한 객체들은 모두 크기가 같고, 어떤 종류의 객체를 가리키는 지에 대한 제약이 존재
: 개별 space들은 page의 연속된 집합으로 구성
: page는 연속적인 메모리 chunk이며, mmap에 의해 OS로 부터 할당됨
: page는 항상 1MB의 크기를 가짐
※ 참조
: https://2mukee.tistory.com/489
Refference
'Programming > NodeJS' 카테고리의 다른 글
express의 구조 (0) | 2023.02.13 |
---|---|
NodeJS와 메모리 2 - 가상메모리와 힙 / 스택 (0) | 2022.09.12 |
NodeJS --inspect (NodeJS 디버깅 / 힙 스냅샷 생성하고 분석 하기) (0) | 2022.09.01 |
클러스터링을 이용한 멀티쓰레드 IPC (0) | 2022.08.31 |
NodeJS memory leak 추적하는 방법 (메모리를 낭비하는 함수 추적) (0) | 2022.08.26 |