본문 바로가기
프로그래밍/JavaScript

V8 Engine에 대해서....(메모리구조, 컴파일방식)

by Hwan2 2021. 5. 31.
728x90
반응형



 

1. V8 Engine이란??

Google에서 만든 JavaScript 컴파일러로 C++언어를 기반으로 만들어 졌습니다.
때문에 독립적으로 실행이 가능하며, 다른 웹 브라우저 없이 JavaScript, Node.js 코드를 컴파일 할 수 있습니다.

2. JIT Compiler (Just-In-Time)

V8은 JIT Compiler을 지원합니다.
일반적인 Compiler에는 동적 컴파일(인터프리터)와 정적 컴파일(Compiler)가 있습니다.

JIT Compiler는 이 두개를 합친 것으로 실행시점에서 인터프리터 방식으로 바이트 코드를 생성합니다.
그 후 V8 Engine은 바이트 코드를 기계어 코드로 만들고, 그 코드를 캐싱하여, 같은 함수가 여러 번 불릴 때 매번 기계어 코드를 생성하는 것을 방지합니다.
(인터프리터 방식은 한줄읽고 실행하는 방식으로, 동일한 동작을하는 함수가 여러번 나오더라도 이를 컴파일 하는 과정을 거치게 됩니다. 따라서 이는 매우 비효율적이며, JIT Compiler는 이를 방지하여 위와 같은 동작으로 실행되게 됩니다.)

V8 Engine에서 바이트코드로 바꾸는 컴파일러를 Ignition 이라고 말합니다.
https://v8.dev/blog/ignition-interpreter

 

Firing up the Ignition interpreter · V8

V8 and other modern JavaScript engines get their speed via just-in-time (JIT) compilation of script to native machine code immediately prior to execution. Code is initially compiled by a baseline compiler, which can generate non-optimized machine code quic

v8.dev


이렇게 빠르고 효율적인 컴파일러이기 때문에 Just-In-Time이라고 불리게 됩니다.
이를 통해 얻을 수 있는 이점이 있는데,

  1. 복잡한 최적화 과정은 바이트코드 컴파일러가 대신 해주므로 고려하지 않아도 된다.
  2. 바이트코드는 빠른 기계어 변환을 목적으로 설계되었기 때문에 일반적인 컴파일러보다 제작 과정이 수월하다.

참고 : https://ko.wikipedia.org/wiki/JIT_%EC%BB%B4%ED%8C%8C%EC%9D%BC

 

JIT 컴파일 - 위키백과, 우리 모두의 백과사전

위키백과, 우리 모두의 백과사전. JIT 컴파일(just-in-time compilation) 또는 동적 번역(dynamic translation)은 프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일 기법이다. 전통적인 입장에서 컴

ko.wikipedia.org

 

3. JavaScript Engine AST

JavaScript는 인터프리터 되는 과정을 거치기 전에, 해당 소스코드를 parser -> Abstract Syntax Tree 형태로 바꾸게 됩니다.

parser는 구문 분석기로 해당 소스가 컴파일 되기 전에 parser로 소스를 공급해주면, 소스를 분석하여 구문 분석을 수행하고, 수행한 결과를 가지고 AST(추상 구문 트리)를 생성합니다.

JavaScript의 parser는 lazy parser를 사용하는데, lazy parser의 궁극적인 목표는 중복되는 함수에 대한 처리와 만나는 함수를 사전에 구문 분석함으로써 함수를 건너 뛸 수 있도록 하는 작업을 수행합니다. 이러한 최적화 과정을 거친 후 컴파일러 알고리즘에 서 많이 사용되는 AST자료구조를 사용하여 컴파일 작업을 돕게 됩니다.

참고 :
https://ariya.io/2012/07/lazy-parsing-in-javascript-engines

 

Lazy Parsing in JavaScript Engines

Modern JavaScript engines can defer the parsing process of a function body until it is completely needed. Why is this done and how does this work?

ariya.io

https://v8.dev/blog/preparser

 

Blazingly fast parsing, part 2: lazy parsing · V8

This is the second part of our series explaining how V8 parses JavaScript as fast as possible. The first part explained how we made V8’s scanner fast. Parsing is the step where source code is turned into an intermediate representation to be consumed by a

v8.dev

https://mathiasbynens.be/notes/shapes-ics

 

JavaScript engine fundamentals: Shapes and Inline Caches · Mathias Bynens

This article describes some key fundamentals that are common to all JavaScript engines — and not just V8, the engine the authors (Benedikt and Mathias) work on. As a JavaScript developer, having a deeper understanding of how JavaScript engines work helps

mathiasbynens.be

 

4. V8 Engine Memory Structure


V8 Engine의 메모리구조는 Stack과 Heap 두가지 영역으로 나뉘게 됩니다.
Heap에 올라간 데이터들은 New와 Old영역으로 나뉘며 GC를 통해 관리되게 됩니다.(JVM GC와 비슷한 구조입니다.)

Code-space : JIT (Just In Time) 컴파일러가 컴파일된 코드 블록을 저장하는 곳입니다.
이곳은 실행 가능한 메모리가있는 유일한 공간입니다.

Heap에 올라가는 것들은 주로 Object가 올라가게 됩니다.

전역 스코프, 함수를 호출했을 때의 영역, Objcet를 참조하고 있는 변수들은 Stack 영역에 할당되게 됩니다.

Stack영역은 Frame이라는 단위로 묶여서 올라가며, 처음 컴파일 될 때 Global frame이라는 스택 제일 아랫 영역에 전역 스코프나 기타 참조 변수들을 넣습니다.

그 후 함수가 호출이 되면 해당 함수 이름으로된 Frame영역이 생기며, 함수가 끝나기 전까지 해당 Frame영역에 변수들이 적재됩니다. 해당 함수에서 객체를 정의한다면, 생성됨과 동시에 해당 객체를 Heap에 할당하며, 스택에 입력된 값들을 Heap에 복사되어 넣게 됩니다.

https://speakerdeck.com/deepu105/v8-memory-usage-stack-and-heap

 

V8 Memory usage(Stack & Heap)

 

speakerdeck.com

해당 그림 좌측 하단에 화살표시가 있는데, 사진을 넘겨보면서 어떻게 동작하는지 보시면 이해하기 수월할 것입니다.

참고 :
https://deepu.tech/memory-management-in-v8/

 

🚀 Visualizing memory management in V8 Engine (JavaScript, NodeJS, Deno, WebAssembly)

Let us take a look at how the V8 engine for JavaScript & WebAssembly manages memory for Browsers and NodeJS.

deepu.tech

 

5. Stack?? Call Stack??

구글링 검색을 많이하다보면 어떤곳은 Stack이라 부르고, 어떤곳은 Call Stack이라 부릅니다.

사실 둘다 같은 의미이며, 그냥 일반적인 Stack으로 생각하시면 됩니다.

많이들 착각하는것이, "JavaScript는 단일쓰래드이며, Call Stack을 기반으로 비동기 처리가 된다" 라는 말이 있는데,
이는 반쪽자리 정답입니다.

우선 JavaScript는 Single Thread는 맞습니다. 때문에 Event Loop를 사용하여, Callback 함수들의 변화를 기다리죠.
그리고 이 Callback되는 순서들을 저장하는 곳은 Event Queue입니다.

Stack은 일반적인 의미로 다른 컴파일러에서 사용되는 Stack과 동일한 기능을 합니다.
즉, 함수가 호출되면 Stack에 쌓이고, 함수 호출이 끝나면 Stack에서 POP되고....

단, JavaScript는 하나의 언어로 이뤄진 것이 아니라, DOM + BOM + ECMAScript로 이뤄져있는 하나의 Script 언어 입니다. 이뿐만 아니라 AJAX, setTimeout등 브라우저에서 제공해주는 web API를 많이 사용합니다.
그리고 그 속에 Event Loop와 Event Queue가 있으며, 이들이 비동기처리를 도와주게 됩니다.
(물론 Stack에 쌓인 함수 Frame을 기준으로 Event Queue에 적제 되겠지만요.... 비동기시 주체가 되는 것은 Stack이 아니라 Queue입니다.)


잘못된 설명이 있다면 댓글로 피드백 남겨주세요!!


이상입니다.!!




반응형

댓글


스킨편집 -> html 편집에서