본문 바로가기
개발/자바스크립트

[자바스크립트] 자바스크립트의 동작에 대하여 #2(V8 엔진, 최적화 팁 5개)

by 핸디(Handy) 2021. 3. 29.

2021.03.26 - [개발/자바스크립트] - [자바스크립트] 자바스크립트의 동작에 대하여 #1(feat.엔진, 런타임, 콜스택)

다음 포스트 V8 엔진, 최적화 팁 5개에 대해 추가적으로 살펴보겠다.

일단 이 글은 blog.sessionstack.com/how-javascript-works-inside-the-v8-engine-5-tips-on-how-to-write-optimized-code-ac089e62b12e 를 토대로 작성한 것이다.


우선 자바스크립트의 엔진에 대해 살펴보기 전에 브라우저의 전체 구조를 한번 살펴보겠습니다.

브라우저를 구성하는 다양한 레이어들.

사용자 인터페이스(UI) 레이어는 인터넷 창을 딱 열었을 때 보이는 상단 레이어다. 주소창, 뒤로 가기, 앞으로 가기, 새로고침, 북마크, 환경설정과 같은 UI가 해당된다.

브라우저 엔진은 사용자 인터페이스와 렌더링 엔진 사이에서 중개자 역할을 한다. 사용자 인터페이스를 통해 들어온 액션이 이것을 해석하여 적절한 명령을 수행하거나 전달한다.

렌더링 엔진은 HTML과 CSS, JavaScript를 파싱 하고 그 결과물을 바탕으로 페이지를 그려내는 레이어다.. 각 브라우저는 별로 다양한 엔진이 있으며 렌더링 엔진도 최적화를 하는데에 아주 중요한 부분이다.

네트워크 레이어는 HTTP나 HTTPS 같은 프로토콜을 이용해 외부의 리소스를 얻어오고, 서버에 요청을 보낼 때 사용되는 레이어이다.

JavaScript 인터프리터는 JavaScript를 해석하고 실행하는 역할을 하며 이번 포스트의 메인이 되는 레이어다.

UI 백엔드는 브라우저가 동작하고 있는 운영체제의 인터페이스를 따르는 UI들을 처리합니다. 얼럿(alert)이나 셀렉트 박스(select) 등이 예다.

자료 저장소는 브라우저 자체에서 하드디스크와 같이 데이터를 로컬에 저장하기 위한 레이어로, 쿠키나 로컬 스토리지, 세션 스토리지, indexedDB, 웹 SQL, 파일 시스템 등에 접근하고 데이터를 저장하는데 쓴다.

이렇게 다양한 레이어들이 있고 우리는 앞선 글에 이어 이번에도 자바스크립트 엔진에 대해 알아보고 있다. 여기서 말하는 엔진이란

자바스크립트 코드를 실행하는 프로그램, 즉 자바스크립트 인터 프린터를 말한다. 자바스크립트 엔진은 표준적인 인터프리터로 구현될 수도 있고 자바스크립트 코드를 바이트 코드로 컴파일하는 JIT 컴파일러로 구현할 수 있다.

따라서 표준적인 인터 프린터로 구현된다고 하더라고 각각의 내부 구현은 상이할 수도 있음을 확인했었다.(sort 알고리즘을 예시로)

다양한 자바스크립트 엔진 중에 가장 유명한 엔진은 크롬의 V8 엔진이다.

V8 엔진은 구글에서 만들었으며, 오픈소스이고 C++로 제작된 Javascript, WebAssembly 엔진이다.

또한 우리에게 익숙한 브라우저인 크롬에서 사용 중이다. 특이한 점은 다른 엔진과 달리 Node.js의 런타임으로도 사용된다는 점이다.

 

V8 JavaScript engine

What is V8? V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++. It is used in Chrome and in Node.js, among others. It implements ECMAScript and WebAssembly, and runs on Windows 7 or later, macOS 10.12+, and Linu

v8.dev

 


이제 5가지 최적화 팁에 대해 설명해보겠다.

  1. 객체 속성의 순서: 객체 속성을 항상 같은 순서로 초기화해서 히든 클래스 및 이후에 생성되는 최적화 코드가 공유될 수 있도록 합니다
  2. 동적 속성: 객체 생성 이후에 속성을 추가하는 것은 히든 클래스가 변하도록 강제하고 이전의 히든 클래스를 대상으로 최적화되었던 모든 메서드를 느리게 만듭니다. 대신에 모든 객체의 속성을 생성자에서 할당합니다
  3. 메서드: 동일한 메서드를 반복적으로 수행하는 코드가 서로 다른 메소드를 한 번씩만 수행하는 코드보다 더 빠르게 동작합니다(인라인 캐싱 때문)
  4. 배열: 값이 띄엄띄엄 있어서 키가 계속해서 증가하는 숫자가 되지 않는 배열은 피하는 게 좋습니다. 모든 요소를 가지지는 않는 배열은 해시 테이블입니다. 이와 같은 배열의 요소들은 접근하기에 많은 비용이 듭니다. 또한 커다란 배열을 미리 할당하지 않도록 하십시오. 사용하면서 크기가 커지도록 하는 게 낫습니다. 마지막으로 배열의 요소를 삭제하지 마십시오. 그 배열의 키가 띄엄띄엄 배치됩니다.
  5. 태깅된 값: V8은 객체와 숫자를 32비트로 표현합니다. 어떤 값이 오브젝트(flag = 1)인지 혹은 정수(flag = 0)인지는 SMI(Small Integer)라는 하나의 비트에 저장하고 이 때문에 31비트가 남습니다. 따라서 어떤 숫자가 31비트 보다 크면 V8은 이 숫자를 분리해서 더블 타입으로 전환한 다음 이 숫자를 넣을 새로운 객체를 생성합니다. 이러한 동작은 비용이 높으므로 가능한 한 31비트의 숫자를 사용하도록 하십시오.

<추가 자료>
wormwlrm.github.io/2021/03/27/How-browsers-work.html

댓글