자바스크립트 엔진

JavaScript 엔진은 Stack 메모리와 Heap 메모리를 사용하며 싱글 스레드로 모든 코드를 수행한다.

 

 

자바스크립트 엔진의 Stack 은 일반 프로그램 언어들의 Stack 과는 다르다.

타 프로그램 언어들은 함수 실행에 따라 Call Stack 에 각 로컬 함수들의 변수 등의 Context 정보들을 다 같이 쌓으며,

로컬 함수에만 국한된 정보들을 갖는다는 이유로 Context 를 Scope 라고도 부른다.

 

자바스크립트 엔진도 Call stack 에 함수 호출 순서를 적재하지만,

변수 및 함수 선언과 할당 정보는 Heap 에 따로 저장하여 Call Stack 에는 본 Heap 에 대한 포인터만 갖고 있다.

구체적으로 정리하면 아래와 같다.

 

  1. Heap: 각 함수 별 선언 및 할당되는 모든 변수 및 함수를 적재하는 메모리 영역
  2. Stack(Call Stack): 함수 실행 순서에 맞게 위 Heap 에 대한 포인터 적재 및 실행

자바스크립트 엔진 실행 과정

자바스크립트 엔진 실행 과정은 (A) JIT 컴파일 단계 (B) 수행 단계 이렇게 두 개로 나뉜다.

(A) 컴파일 과정

컴파일 과정에선 변수 및 함수의 '선언(Declaration)'만 추출하여 Heap 에 적재한다.
변수와 함수의 선언을 자바스크립트 실행 이전에 컴파일로 저장하여 실제 실행 시 변수와 함수 선언 여부를 검색한다.

 

예를 들어 아래 자바스크립트 파일을 처음 실행하게 되면 파일 전체에 컴파일 단계를 수행한다.

var a = 2;
b = 1;

function f(z) {
  b = 3;
  c = 4;
  var d = 6;
  e = 1;

  function g() {
    var e = 0;
    d = 3*d;
    return d;
  }

  return g();
  var e;
}

f(1);

 

1. 자바스크립트 첫 실행을 위한 main() 함수의 Global Scope(window) 영역을 Heap 에 생성한다.

# Global Scope (window)
- 
-

2. 변수 선언 var a을 찾아서 Global Scope(window) 영역에 a 를 적재한다.
3. 변수 할당 b = 1은 할당이므로 본 영역에 b 를 적재하지 않는다.

# Global Scope (window)
- a =
-

4. 함수 선언 function f(z)을 찾아서 Global Scope(window) 영역에 f 를 적재한다.
5. 함수 적재시엔 f 함수의 바이트코드(blob)에 대한 포인터값을 함께 적재한다.

 

자바스크립트 코드를 첫번째 라인에서 20번째 라인까지 컴파일 단계를 마치면 Heap 구성은 아래와 같다.

# Global Scope (window)
- a =
- f = a pointer for f functions bytecode

 

(B) 수행 과정

수행 과정에선 변수의 '할당(Assignment)'값들을 Heap 에 적재하고 함수는 호출 및 실행한다.

 

매 함수 호출때마다 스택에 함수 내 변수 및 함수를 같이 적재하는 스택 베이스 언어과 달리

자바스크립트는 스택에는 함수 호출 순서와 실제 변수 및 함수 정보들은 Heap 에 대한 포인터를 갖는다. 

Heap 에 함수 a() 를 위한 Local Execution Scope 는 a() 함수가 호출되기 이전에 Heap 에 존재했던

Global Scope(window)에 대한 포인터를 갖고있어서 엔진 내에서 아래와 같은 처리가 가능하다.

  • a() 함수 내에서 a = 1 변수 할당 시 먼저 Local Execution Scope 에 a 변수의 선언을 찾고,
    존재하지 않는다면 이전 Global Scope 로 돌아가 검색할 수 있다.
  • a() 함수 실행이 끝나게 되면 Call Stack 을 통해 현재 Heap 영역을 Global Scope 로 다시 되돌린다.


위에서 예시로 살펴본 자바스크립트 파일에 컴파일 단계를 마친 뒤 수행 단계는 아래와 같이 진행된다.

6. 컴파일 이후 아래의 Heap 을 갖고 다시 자바스크립트 파일 코드의 맨 첫번째 라인에서 실행이 시작된다.

# Global Scope (window)
- a =
- f = a pointer for f functions bytecode

7. 변수 할당 a = 2을 찾아서 Global Scope (window) 영역에 변수 a 존재 여부를 확인한다.
8. 변수 a 가 존재하므로 해당 a 에 2 를 할당한다.

# Global Scope (window)
- a = 2
- f = a pointer for f functions bytecode

9. 변수 할당 b = 1을 찾아서 Global Scope (window) 영역에 변수 b 존재 여부를 확인한다.
10. 변수 b 가 선언되어있지 않아 b 선언 및 1 을 할당한다.

# Global Scope (window)
- a = 2
- f = a pointer for f functions bytecode
- b = 1

11. 함수 호출 f(1)을 찾아서 Global Scope(window)영역에서 f() 선언 여부를 확인한다.
12. 함수 f() blob 컴파일 및 수행을 위해 Heap 에 새 Local Execution Scope 영역을 생성한다.

# Global Scope (window)
- a = 2
- f = a pointer for f functions bytecode
- b = 1

# Local Execution Scope for f()
- (hidden) A pointer for previous scope (= Global Scope (window))
- 
-

f(1) 함수 실행 시 새로이 생성된 Local Execution Scope에 다시 컴파일 단계를 통해  변수와 함수를 적재하고 수행 단계을 거친다.

또 f(1) 함수 내부에 또 다른 함수가 있다면 이 과정을 계속해서 재귀적으로 반복한다.

13. 함수 f() 의 컴파일 단계를 마치면 아래와 같다.

# Global Scope (window)
- a = 2
- f = a pointer for f functions bytecode
- b = 1

# Local Execution Scope for function f()
- (hidden) a pointer for previous scope (= Global Scope (window))
- z = 
- d = 
- e =

14. 함수 f() 의 수행 단계를 마치면 함수 f() 내 변수 할당 및 함수 g() 의 Scope 가 생성된다.

# Global Scope (window)
- a = 2
- f = a pointer for f functions bytecode
- b = 3

# Local Execution Scope for function f()
- (hidden) a pointer for previous scope (= Global Scope (window))
- z = 1
- d = 6
- e = 1
- c = 4

# Local Execution Scope for function g()
- (hidden) a pointer for previous scope (= Local Execution Scope for function f())
- e =

 

 

 

출처)

 

Javascript 엔진 개요 및 실행 과정으로 살펴보는 Hoisting 과 Closure

자바스크립트자바스크립트는 웹 페이지의 세 요소중 하나입니다. HTML: 웹 페이지(문서) 포맷을 정의하는 마크업 언어 CSS: 웹 페이지(문서)의 디자인 요소에 대한 언어 Javascript: 웹 페이지(문서)와

aaronryu.github.io

 

+ Recent posts