V8 Engine에 대해 알아보자.
V8 Engine이란?
Google Chrome과 Node.js에서 사용하는 자바스크립트 엔진입니다.
일반적인 Javascript 엔진은 한 줄씩 해석하고 실행하는 인터프리터 형식이지만, V8 엔진은 바이트코드로 컴파일한 후 실행하는 방식을 사용합니다.
JIT 컴파일러 (Just-In-Time)
V8 Engine이 속도 개선을 위해 적용한 컴파일러입니다.
일반적인 컴파일러에는 동적 컴파일(인터프리터)와 정적 컴파일(Compiler)가 있습니다.
JIT는 이 두가지를 혼합한 형식으로 실행시점에서 인터프리터 방식으로 바이트 코드를 생성
하고 그 코드를 캐싱
하여 같은 함수가 여러 번 불릴 때 매번 같은 기계어 코드를 생성하는 것을 방지
합니다.
동작 순서
Parser
낱말 분석(Lexical Analysis) 이라는 과정을 통해 코드를 토큰으로 분해한다.- 브라우저렌더링 방식과 유사합니다.
- JS로 되어있는 소스코드를 Parser 가 넘겨받아 AST(Abstract Syntax Tree) 를 생성해준다.
( 마치 HTML 을 파싱하여 DOMTree 를 만들어주는 HTML Parser 와 유사합니다. )
Ignition
AST를 ByteCode로 변환합니다.High Level의 소스코드를 가상 머신이 이해하기 쉬운 중간 코드로 변환합니다.
(기계어보다는 추상적인 코드)인터프리터 방식으로 진행됩니다.
ByteCode가 주는 이점
메모리 사용량 감소
JS 를 기계어로 한번에 컴파일 하는것보다 바이트코드로 변환하는것이 메모리 점유율이 낮습니다.파싱 시 오버헤드 감소
컴파일 파이프 라인의 복잡성 감소
Optimizing이든 Deoptimizing이든 바이트 코드 하나만 생각하면 되기 때문에 편하다.
TurboFan
최적화 담당 컴파일러입니다.
런타임 중에 Profiler 라는 기능을 하는 도구가 여러 데이터를 수집하고 TurboFan이 수집한 데이터를 받아서 Optimized Machine Code, 즉 최적화된 코드로 다시 컴파일합니다.최적화 기법
히든 클래스
데이터를 사용하는 부분에 있어서 데이터를 직렬화하고, 데이터의 위치정보(property)는 따로 만들어서 최적화한다.인라인 캐싱
동일한 객체가 계속 리턴되는 함수가 있다면, 해당 함수를 optimized code 로 만들어서 쓰기 편하게 리턴되는 객체자체로 변환한다.
Memory Structure
Stack과 Heap 두 영역으로 나누어집니다.
Heap에는 주로 Object가 올라가게 됩니다.
Stack에는 주로 전역 스코프, 함수 호출했을 때의 영역, Objcet를 참조하고 있는 변수들이 할당되게 됩니다.
Stack영역은 Frame이라는 단위로 묶여서 올라가며, 처음 컴파일 될 때 Global frame이라는 스택 제일 아랫 영역에 전역 스코프나 기타 참조 변수들을 넣습니다.
그 후 함수가 호출이 되면 해당 함수 이름으로된 Frame영역이 생기며, 함수가 끝나기 전까지 해당 Frame영역에 변수들이 적재됩니다.
해당 함수에서 객체를 정의한다면, 생성됨과 동시에 해당 객체를 Heap에 할당하며, 스택에 입력된 값들을 Heap에 복사되어 넣게 됩니다
참고 사이트