v8은 자바스크립트 코드를 어떻게 해석하고 실행할까?
💡 V8엔진의 가장 큰 차이점은 JIT(Just In Time) 컴파일러다. → JIT 컴파일러
- 소스 코드를 가져와서 parser에게 넘긴다.
- parser는 코드를 분석한후 AST, 추상 구문 트리로 변환한다
- 그다음 AST를 자바스크립트를 바이트코드로 변환하는 인터프리터(ignition)로 넘긴다.
- 컴퓨터가 이해할 수 있는 바이크 코드로 변환이 되었기에 이 바이트 코드를 실행함으로 실제 코드가 작동이 된다. 프로파일러(profiler)라는 곳에서 일정기준이상 동일한 함수가 호출되면 최적화가 가능하다고 판단하고 해당 코드를 컴파일러(TurboFan)로 보내 최적화된 코드(Optimized Machine Code)로 컴파일한다.
- 그러다 사용이 덜 된다 싶으면 Deoptimizing이 되기도 한다.
➡️ 인터프리터에 의해 하나씩 웹사이트가 구동되는 동안 필요한 부분을 기계어로 변환해서 최적화를 진행하고 그 최적화된 코드를 수행할 차례가 되면 Bytecode가 아닌 최적화된 Machine Code를 실행하기에 구동속도가 더 빨라지게 되는 것이다
🔥 ignition🔥
➡️ 엔진에서 점화부분을 담당. 실제 코드가 실행되기 위해 엔진에 점화를 하는 단계이다. 그전에는 한 번에 컴파일해야 해서 메모리 사용량이 컸었기에 한 줄씩 바이트코드로 변환해 줄 ignition이 필요해진 거야
🔥TurboFan 🔥
➡️ 코드가 많이 실행돼서 엔진이 뜨거워지면 TurboFan으로 가서 과열되지 않게 최적화를 통해 식혀 준다. ignition에서 만들어진 바이트코드를 기반으로 히든클래스와 인라인 캐싱을 통해 최적화를 진행한다(자세한 내용은 다음번에 다뤄보도록 하겠습니다 🤭)
간단히 말하면 히든클래스는 비슷한 내용은 분류해서 재사용할 수 있게끔 하는 것이고 인라인 캐싱은 함수의 호출만 되어 있는 부분을 아예 함수의 내용 포함하게끔 바꾸는 것이다.
🔥 Bytecode 🔥
➡️ 고급언어로 작성된 코드를 컴퓨터가 이해하기 쉽게 중간 코드로 한번 컴파일한 것을 의미한다. Ignition이 이것을 담당하고 있으며 이것은 모든 소스를 한 번에 해석하는 컴파일 방식이 아닌 한 줄 한줄 실행될 때마다 해석하는 인터프리트방식을 택한 인터프리터이다
인터프리터: 코드를 한 줄 한 줄 읽어 내려가며 한 줄씩 Bytecode로 변환한다.
컴파일러: 한 줄씩이 아니라 파일 전체를 읽은 뒤, 코드의 의미를 해석하고 파일 전체를 기계어(Machine Code)로 컴파일해서 변환한다.
왜 자바스크립트는 인터프리터 방식을 택했을까?
자바스크립트는 웹을 위해 개발된 언어이기에 유저에게 다양한 요청에 있어서 빠르게 실행되는 것을 응답해줘야 하기에 코드 전체가 컴파일되기를 기다리는 게 아닌 한 줄 한줄 변환하는 인터프리터 방식이 더욱 알맞은 것이다.
마치며
특히 TurboFan이 어떻게 작동하는지 살펴보고 그것을 바탕으로 나의 자바스크립트 코드를 최적화하는 방법에 대해 생각해봐야 할 것 같다. 단순히 작동하는 코드를 적어 내려 가는 것뿐만 아니라 효율적이고 생산적인 코드를 짤 수 있는 있기를 바라며 다음번에는 심화버전으로 다시 찾아올 것을 약속합니다.
참조
https://velog.io/@dalbodre/V8-엔진의-과거-현재-구조
'TIL' 카테고리의 다른 글
동기 / 비동기 (0) | 2023.03.27 |
---|---|
Libuv 라이브러리(feat. 이벤트 루프) - 3 (0) | 2023.03.24 |
나는 왜 Node.js를 사용했을까? - 1 (0) | 2023.03.15 |
Process & Thread (0) | 2023.03.13 |
API가 도대체 뭐야? 이걸로 끝내자 (0) | 2023.03.10 |