자바스크립트 엔진
JavaScript 엔진은 Stack 메모리와 Heap 메모리를 사용하며 싱글 스레드로 모든 코드를 수행한다.
자바스크립트 엔진의 Stack 은 일반 프로그램 언어들의 Stack 과는 다르다.
타 프로그램 언어들은 함수 실행에 따라 Call Stack 에 각 로컬 함수들의 변수 등의 Context 정보들을 다 같이 쌓으며,
로컬 함수에만 국한된 정보들을 갖는다는 이유로 Context 를 Scope 라고도 부른다.
자바스크립트 엔진도 Call stack 에 함수 호출 순서를 적재하지만,
변수 및 함수 선언과 할당 정보는 Heap 에 따로 저장하여 Call Stack 에는 본 Heap 에 대한 포인터만 갖고 있다.
구체적으로 정리하면 아래와 같다.
- Heap: 각 함수 별 선언 및 할당되는 모든 변수 및 함수를 적재하는 메모리 영역
- 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
'언어 > JavaScript' 카테고리의 다른 글
[JavaScript] 스코프 체인과 호이스팅 (0) | 2023.12.01 |
---|---|
[JavaScript] async 와 await (0) | 2023.11.04 |
[JavaScript] Promise 객체 등장 배경 (0) | 2023.11.03 |
[JavaScript] const 와 불변(immutable) (0) | 2023.10.27 |