자바스크립트 엔진 - V8

2020. 3. 2. 15:11웹/Javascript

V8 엔진

  • 웹 브라우저를 만드는데 기반을 제공하는 오픈 소스 자바스크립트 엔진

  • C++ 작성된 고성능의 자바스크립트 & 웹 어셈블리어 엔진

 

 

동작 과정

  • 일반적인 자바스크립트 엔진 동작 과정

 이미지 출처 :https://mathiasbynens.be/notes/shapes-ics

  • V8 엔진  동작 과정

 이미지 출처 :https://mathiasbynens.be/notes/shapes-ics

 

  1. Javascript Code 작성
  2. Javascript Code를 파서(Parer)가 파싱

  3. AST(Abstract Syntax Tree) 생성

  4. 생성된 AST를 Ignition 에게 전달

    V8 엔진의 인터프리터를 Ignition 이라고 하며 바이트 코드 생성(Bytecode) 및 실행을 담당.

    원본 소스 코드 보다 컴퓨터가 이해하기 쉬운 바이트 코드로 변환함으로써 원본 코드를 다시 파싱(Parsing) 해야 하는 수고를 덜고 코드의 양도 줄이면서 코드 실행 때 차지하는 메모리 공간을 아끼려는 목적.

  5. 바이트 코드를 실행함으로써 소스 코드가 실제 동작, 또한 바이트 코드가 실행하는 동안 프로파일링 데이터를 수집하여 나중에 실행 속도를 높임.

    함수가 자주 실행될 때와 같이 그 중 자주 사용하는 코드(바이트 코드와 프로파일링 데이터)는 TurboFan 으로 전달되어 프로파일링 데이터를 기반으로 최적화된 코드(Optimized Machine Code)로 다시 컴파일 됨.

  6. 만약 정확하지 않은 결과가 나왔다면 다시 바이트 코드로 변경(Deoptimizing)

 

※ Full-codegen 과 Crankshaft

처음으로 Ignition 및 TurboFan은 V8 v5.9의 JavaScript 실행에 보편적으로 독점적으로 사용됩니다. 또한 v5.9 부터 2010 년 이후 V8 을 지원 한 기술인 Full-codegen 및 Crankshaft 는 더 이상 새로운 JavaScript 언어 기능 및 최적화에 보조를 맞출 수 없으므로 V8에서 JavaScript 실행에 더 이상 사용되지 않습니다. 이러한 기능이 필요합니다. 곧 완전히 제거 할 계획입니다. 이는 V8이 전체적으로 훨씬 단순하고 유지 보수가 쉬운 아키텍처를 갖게됨을 의미합니다.

출처 :https://v8.dev/blog/launching-ignition-and-turbofan

 

 

 

최적화 기법

1. 인라이닝(Inlining)

함수가 호출된 지점에 함수의 내용으로 바꾸는 과정

 

 

2. 히든 클래스(Hidden Class)

배경

  • 정적 타이핑 언어

    정적 타이핑 언어는 가변 길이 배열과 같은 동적인 데이터 타입을 사용하지 않는 이상 프로퍼티의 메모리 오프셋을 컴파일 시점에 결정.

    자바는 모든 객체 속성이 컴파일 전에 고정된 객체 레이아웃(Class)에 의해 결정되며 컴파일 시에 메모리 오프셋이 결정. 이후 런타임시에는 객체에 대한 프로퍼티가 동적으로 추가/삭제 될 수 없어 메모리 할당 정도가 변화할 수 없음. 할당된 배열의 시작부터 오프셋에 따라 메모리 주소를 찾아 데이터 접근.

  • 프로토타입 언어(동적 타이핑 언어)

    자바스크립트는 프로토타입 기반 언어이며 동적으로 type이 지정되기 때문에 명시적이지 않음. 또한 proeprty는 직접 객체 추가/삭제 가능. 이러한 특성으로 인해 자바스크립트는 런타임 시에 속성 타입이 결정되며, 기존의 정적타입과 같은 오프셋으로 메모리를 결정지을 수 없음.

    대부분의 JS 인터프리터는 딕셔너리와 유사한 구조를 통해 객체 속성값의 위치를 메모리에 저장.

    이러한 딕셔너리 구조를 통해 모든 객체의 속성에 대한 메모리 주소를 관리하는 것은 가능하지만, 다른 언어보다 메모리 검색 속도가 느리고 매우 비효율적.

    V8 엔진은 Javascript의 동적 탐색을 회피하기 위해 다른 방식 히든 클래스를 이용하여 객체 속성의 위치를 관리.

 

특징

  • 런타임 시 히든 클래스를 생성 됨.

  • 객체는 반드시 하나의 히든 클래스를 참조하며 각 프로퍼티에 대해 메모리 오프셋을 가짐.

  • 동적으로 프로퍼티 추가/삭제/수정 시 신규 히든 클래스생성하여 기존의 프로퍼티 정보를 유지하며 새로운 프로퍼티의 오프셋을 가짐.

  • 객체에 프로퍼티 추가 시, 현재 참고하고 있는 히든 클래스의 전환 정보를 확인한 후 현재 프로퍼티에 대한 변경이 전환 정보의 조건과 일치하면, 객체의 참조 히든 클래스를 조건에 명시된 히든 클래스로 변경(히든 클래스 재활용)

 

※ 동적 탐색

객체에 대한 참조를 관리하는 대책이 따로 없기 때문에, 프로퍼티 값을 읽을 때마다 프로퍼티 위치를 찾는 것

※ 정보 전환

동일한 프로퍼티 구성으로 객체 생성 시, 히든 클래스를 새로 만들지 않고 재활용. 히든 클래스의 효율을 높여주는 정보

 

 

 

3. 인라인 캐싱(Inline Caching)

설명

  • 특정 호출지점에서 발생하는 객체들은 주로 같은 타입이라는 지역적 특성을 이용.
  • V8 엔진은 메소드 호출 인자로 전달된 객체의 타입을 캐시에 유지하고 이 정보를 이용하여 앞으로 넘어올 파라미터의 객체 타입을 추론. 이 추론에 맞으면 객체의 프로퍼티 위치를 탐색하지 않고 히든 클래스를 찾아 저장된 오프셋 정보를 확인.

 

과정

  • 특정 객체가 호출될 때마다 V8 엔진은 특정 프로퍼티에 접근하기 위하여 오프셋 계산을 위해 해당 객체의 히든 클래스를 확인.
  • 동일한 히든 클래스의 동일한 메소드에 대해 두번의 성공적인 호출을 한다면 V8 엔진은 히든 클래스를 찾는 것을 생략하고 스스로 객체 포인터에 프로퍼티 오프셋을 더한다.
  • 이후 해당 메소드에 대한 모든 호출에 대해 V8 엔진은 히든 클래스는 변하지 않았다고 가정하고 이전에 찾아 두었던 오프셋을 이용하여 직접 메모리 주소로 점프.

 

 

 

 

출처 

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

https://evan-moon.github.io/2019/06/28/v8-analysis/

https://engineering.huiseoul.com/자바스크립트는-어떻게-작동하는가-v8-엔진의-내부-최적화된-코드를-작성을-위한-다섯-가지-팁-6c6f9832c1d9

https://corock.tistory.com/467

' > Javascript' 카테고리의 다른 글

DOM(Document Object Model)  (0) 2020.03.05
콜스택과 메모리 힙  (0) 2020.03.05
Javascript Runtime  (0) 2020.03.05
브라우저 랜더링  (0) 2020.03.02
자바스크립트 엔진  (0) 2020.03.02