JAVASCIRPT ENGINE AND RUNTIME

(https://blog.sessionstack.com/how-javascript-works-inside-the-v8-engine-5-tips-on-how-to-write-optimized-code-ac089e62b12e)

위 글에서 참고


자바스크립트의 엔진은 간단하게 자바스크립트의 코드를 실행시켜주는 역할을 한다.

대표적으로 구글 크롬의 V8 Engine 이 있고 다른 브라우저 모두 자신만의 자바스크립트 엔진을 가지고 있다.


엔진은 크게 두가지 부분으로 구성 되어 있다.

1.메모리 힙(memory heap) : 메모리 할당이 이루어 지는 곳이다.


2.콜 스택(call stack) : 코드가 실행되면서 스택이 호출 되는 곳이다.


자바스크립트 엔진과 브라우저 에서 제공되는 web api 그리고 call back queue ,event loops 등 자바스크립트 실행에 필요한 모든 요소들을 runtime 이라고 한다. runtime을 큰 박스라고 생각하면 편하다.


콜 스택 (Call Stack)

자바스크립트는 단일 쓰레드(single- thread) 프로그래밍 언어이다. 따라서 하나의 call stack만을 가져서 한번에 하나씩 일을 처리한다.

기본적으론 콜 스택에선 우리가 프로그램에서 어디에 위치하는지 나타내 주는 데이터 구조이다. 함수가 실행되면 그 함수를 콜 스택 가장 위로 올린다. 함수가 실행된다면 (반환하게 된다면) 그때 그 함수를 제거 한다. 이게 콜 스택이 하는 일이다. 각각의 단계를 stack frame 이라고 한다.


스택 날림(blowing stack) 현상


주로 콜 스택의 최대 크기를 넘었을 때 나타난다.

function foo(){

 foo();

}

foo() ;

주로 재귀 함수에서 나타나는데 실행할 때 마다 자기 자신을 호출해 결국 콜 스택의 최대 크기를 넘어버린 것이다.


단일 쓰레드를 사용 한다는 것은 멀티 쓰레드 기반 프로그래밍 언어 보다는 쉬울 수 있다. 하지만 단일 쓰레드이기에 발생하는 문제가 있다.

콜 스택에 수행할 함수가 있다면 브라우저는 아무것도 할 수가 없다. 그 수행할  함수가 실행 시간이 길어진다면 그동안 랜더링을 할 수도 없고 다른 코드를 수행할 수도 없고 그대로 멈춰버린다.

이렇게 멈춰버리면 대부분의 브라우저 에서는 반응하지 않는 페이지라며 끄거나 기다리거나 선택하라는 에러 메세지를 보낸다.


자바스크립트의 단일 쓰레드의 의한 문제를 해결하기 위한 것이 비동기 콜백이다.(asynchronous callbacks)





 














heap 은 구조화 되지 않은 메모리가 모여있다. 여기엔 응용 프로그램(크롬 , 사파리..) 가 필요한 모든 object가 저장되어 있다.


그럼 어디서 우리 코드가 실행되는지 궁금할 텐데 그 전에 어떻게 코드가 기계어로 컴파일 되는지 부터 알아보자


코드가 기계어로 컴파일 되는 과정에는 compilation 그리고 interpretation  이 있다.

우선 compilation 에 대해 알아보자.

compilation 은 소스 코드의 모든 코드가 한번에 기계어로 변환되고 컴퓨터가 실행할 수 있는 binaray file(이진 파일, portable file , machine code)에 작성된다. 그 후에 실행된다.


interpretation 은 compilation 과 다르게 거치는 파일이 없고 바로 실행된다. 하지만 한 줄 한줄 실행된다. (당연히 기계어로 변환되고 실행된다) 하지만 너무 느리다는 단점 이 있다. google maps 가 너무 느리다면... 


자바스크립트는 원래 순수 interpretation 이였지만 이 방식은 너무 느려 modern javascript 엔진에서는 새로운 방식을 사용한다


Just-in-time(JIT) compilation 

이 방식은 전체 코드가 한번에 기계어로 바뀐다. 그 다음에 바로 실행한다.

compilation과 다른 점은 기계어로 바뀐 파일은 (not poratable) 이다.



우리의 코드가 실행 되는 과정은 다음과 같다.


첫 번째 단계는 parse the code 이다. (본질적인 뜻은 코드를 읽는다.)

code 는 먼저 AST(abstract syntax tree) 라고 불리는 데이터 구조에 의해 분석된다..

코드 각각의 줄을 언어에 의미가 있는 조각들로 분할함으로써 작동된다. (const 나 function)

그 다음엔 이러한 조각들을 트리 구조에 저장한다. 이를 ast 라고 합니다. 이 단계에서 문법 오류 또한 확인한다.


DOM과 구조가 비슷하지만 이 둘은 명백히 다르다. AST는 그저 자바스크립트 엔진이 언어를 더 잘 이해하도록 바꿔준 것이다.

그 다음으로 AST 가 Compilation 되면 just-in-time compilation 때문에 바로 실행된다. 이때 실행은 앞서 말했듯 자바스크립트 엔진 call stack에서 실행된다. 이는 나중에 더 자세히 다루고

이제 실행하고 있으니깐 여기서 끝난다고 생각했지만 아니다. 현대 자바스크립트 엔진은 꽤 영리한 최적화 전략을 가지고 있다. 맨 처음에 빠른 실행을 위해 최적화 되지 않은 기계어 코드를 실행시킨다. 그리고 백그라운드에서 이 코드는 최적화되고 프로그램 실행 중에 또 다시 컴파일 된다. 각 최적화 가 될 때 마다 최적화되지 않은 코드는 간단히 교체된다. 당연히 이 과정은 실행이 끝날 때까지 끊임 없이 반복된다.



자바스크립트의 runtime 에 대해 알아보자.

가장 흔한 건 브라우저 이다. runtime은 자바스크립트와 관련된 모든 것을 넣어둔 박스라고 생각하자. 자바스크립트 runtime의 핵심은 자바스크립트 엔진이다. 엔진이 없으면 runtime 도 없고 자바스크립트 자체가 없다. 하지만 엔진 만으론 부족하다. runtime에는 web APIs 가 있다.  api 에는 DOM과 관련된 모든 것 timer 그리고 console.log 마 저도 api 이다. 따라서 본질적으론 자바스크립트의 기능이 아니라 web apis 의 기능을 자바스크립트의 엔진에 제공 하는 것이다.  자바스크립트는 그저 global window object를 통해 apis 에게 그저 허락을 받을 뿐이다. 


또한 대부분의 엔진은 callback queue 불리는 걸 포함하고 있다. callback queue 에는 모든 callback 함수들을 가진 데이터 구조 이다. eventhandler 함수로 DOM element 중에서 button 을 이용해 특정한 event에 반응하게 했다. 이러한 event handler 함수를 callback function 이라고 부른다. click 이라는 event를 발생시키면 그해 callback function이 callback queue 안에 넣어진다. 만약 CALL STACK이 비워 지면 그때 callback function은 stack으로 전달되고 그때 실행되는 것이다. 

이러한 상황을 event loop 라고 말한다. 단순히 event loop는 callback function을 callback queue 에서 가져와 실행 될 수 있도록 stack 안에 넣어 주는 역할을 한다.

앞서 말했듯 event loop는 자바스크립트의 non-blocking concurency model에 있어서 필수적이다.


















댓글

이 블로그의 인기 게시물

Javascript this keyward

Javascript Object vs Primitives (Primitives vs reference type)

javascript 15 switch statement