요약
v8 엔진은 크롬 브라우저에서 돌아가는 JavaScript엔진으로 “소스코드 - 파싱 - AST - Ignition로 바이트 코드 생성 - 실행 - Turbo Pan 최적화” 순서로 동작된다.
내용
v8은 구글 크롬 브라우저용으로 개발한 JavaScript, WebAssembly 엔진이다.
동작방식
1. 소스 코드 입력
JavaScript 소스 코드를 입력 받는다.
런타임 환경에서 동적으로 로드된다.
2. 파싱
어휘분석 (Lexical Analysis)
자바 스크립트 코드를 토큰으로 분할한다.
변수, 키워드, 연산자, 리터럴 등으로 분할한다.
let x = 10 + 5;
을 토큰 생성하면 다음과 같다.
let 키워드
x 식별자
= 연산자
10 리터럴
5 리터럴
; 세미콜론
스캐너로 입력된 소스 코드를 한 줄씩 읽어서 각 줄에서 토큰 생성을 한다. 이 과정에서는 공백이나 주석은 무시된다.
구문 분석 (Syntactic Analysis)
생성된 토큰을 기반으로 프로그램의 구조를 정의하는 추상 구문 트리(Abstract Syntax Tree, AST)를 생성한다.
let x = 10 + 5;
을 구문 분석 하면 다음과 같다.
{
"type" : "Program" ,
"body" : [
{
"type" : "VariableDeclaration" ,
"declarations" : [
{
"type" : "VariableDeclarator" ,
"id" : {
"type" : "Identifier" ,
"name" : "x"
},
"init" : {
"type" : "BinaryExpression" ,
"operator" : "+" ,
"left" : {
"type" : "Literal" ,
"value" : 10 ,
"raw" : "10"
},
"right" : {
"type" : "Literal" ,
"value" : 5 ,
"raw" : "5"
}
}
}
],
"kind" : "let"
}
],
"sourceType" : "script"
}
의미 분석(Semantics Analysis)
생성된 AST를 기반으로 변수와 함수의 유효성 및 타입 정보를 확인한다.
3. 바이트코드 생성
V8은 생성된 AST를 바이트 코드로 라인 단위로 변환한다.
V8에서 생성된 바이트 코드는 2가지 주요 요소를 포함한다.
인터프리터 Ignition에서 실행한다.
V8이 지원하는 명령어 집합으로 표현된다.
let x = 10 ;
let y = 20 ;
let sum = x + y;
위 코드를 바이트 코드로 표현하면 다음과 같다. (파싱은 끝났다고 가정한다.)
LOAD_CONST 10 // x에 10을 로드
STORE_VAR x // x에 값을 저장
LOAD_CONST 20 // y에 20을 로드
STORE_VAR y // y에 값을 저장
LOAD_VAR x // x 값을 로드
LOAD_VAR y // y 값을 로드
ADD // 두 값을 더함
STORE_VAR sum // sum에 결과를 저장
4. 실행
생성된 바이트코드를 V8의 Ignition이 실행한다.
인터프리터 형식으로 라인 단위로 실행된다.
함수 호출시 V8은 새로운 스택 프레임 을 생성한다.
스택 프레임은 함수의 실행 컨텍스트(변수, 매개변수, 호출 스택 등)을 유지한다.
각 명령어에 해당하는 작업은 다음과 같다.
변수 로드
연산 수행
조건문 및 반복문 처리
함수 호출
프로파일링
Ignition는 코드가 실행되는 동안 성능 데이터를 수집한다.
자주 호출 되는 함수나 코드 경로에 대한 정보를 바탕으로 최적화가 필요한 코드를 식별한다.
5. 최적화
JIT 컴파일 (Just-In_Time Compilation)
자주 실행되는 바이트코드(hotcode)를 Turbofan이라는 JIT 컴파일러를 사용하여 최적화된 기계어 코드로 변환한다.
다음과 같은 최적화 기법이 사용된다.
인라인 캐싱: 객체의 프로퍼티 접근을 최적화한다.
타입 특화: 타입 정보를 활용하여 해당 타입에 맞는 코드를 생성한다.
불필요한 코드 제거: 실행되지 않는 코드나 불필요한 연산을 제거한다.
가비지 컬렉터
사용되지 않는 메모리를 회수하여 메모리 누수를 방지하고 효율적인 메모리 관리를 보장한다.
Mark-and-Sweep 알고리즘으로 객체의 참조 그래프를 탐색하여, 살아 있는 객체를 마크한다. 이후 마크되지 않는 객체는 메모리에서 해제 된다.
Generation Garbage Collection, 객체의 생명 주기에 따라 세대별로 관리하여 단기 객체와 장기 객체를 구분한다. 짧은 생명 주기를 가진 객체는 자주 수집하고, 긴 생명 주기를 가진 객체는 덜 수집한다.
v8에서 프로그램이 실행되면 메모리의 Resident Set이라는 빈 공간이 할당된다. 스택 영역과 힙 영역으로 나눌 수 있다. (자바스크립트는 싱글 쓰레드라고 하나의 스택 메모리를 가진다.)
힙 - New space는 새로 만들어진 Object가 저장된다.
힙 - Old space는 마이너 가비지 컬렉션이 2번 발생할 동안 살아남은 객체 들이 저장된다.
Pointer space: 다른 객체를 참고하는 객체(다른 객체의 포인터를 가진 객체)
Data space: 문자열, 실수 등 데이터만을 가진 객체
참고