자바스크립트 작동원리

Hyun Kyung Nam·2024년 1월 31일
0

개념정리

목록 보기
1/14
post-thumbnail

자바스크립트 작동원리

참고블로그
1. JavaScript | 자바스크립트 작동 원리(Event Loop와 Call Stack, Web API, Callback Queue)
2. 완벽히 이해하는 동기/비동기 & 블로킹/논블로킹
3. 위키피디아

고급언어로 작성된 프로그램을 실행하는 방법

  1. 프로그램을 인터프리터에 통과시키는 방법
  • 기계어 명렁어들이 만들어지는 컴파일 단계를 거칠필요가 없기 때문에 원시프로그램의 크기가 커도 즉시 실행이 가능
  • 프로그램의 개발단계에서 사용, 프로그래머가 한번에 적은 양의 내용을 추가하고 그것을 빠르게 테스트해보길 원하기 때문이다.
  1. 프로그램 컴파일
  • 일반적으로 인터프리터를 이용해 실행시키는 것보다 더 빠르게 실행
  • 원시프로그램의 크기가 크면 컴파일 과정에 상당한 시간이 걸릴 수 있음

JIT컴파일 : just-in-time compliation 또는 dynamic translation은 프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일 기법
자바 컴파일러가 자바 프로그램 코드를 바이트 코드로 변환한 다음, 실제 바이트 코드를 실행하는 시점에서 자바가상머신이 바이트코드를 JIT컴파일을 통해 기계어로 변환한다.
최근의 JVM(자바가상머신), .NET, V8(node.js)에서는 JIT 컴파일 지원

바이트코드 컴파일러는 소스 코드를 중간언어인 바이트 코드로 변환. 바이트코드는 기계어는 아니지만 가상머신에 의해 기계어로 손쉽게 변환할 수 있는 코드. JIT컴파일러는 바이트 코드를 읽어 빠른 속도로 기계어를 생성할 수 있다. 이런 기계어 변환은 코드가 실행되는 과정에서 실시간으로 일어나며(just-in-time) 전체코드의 필요한 부분만 변환한다. 기계어로 변환된 코드는 캐시에 저장되기 때문에 재사용시 컴파일을 다시 할 필요가 없다.

일반적인 인터프리터 언어(cpython등)는 바이트코드나 소스코드를 최적화 과정이 없이 번역하기 때문에 성능이 낮다. 반면 정적으로 컴파일하는 언어(c언어 등)는 실행 전에 무조건 컴파일을 해야하기 때문에 다양한 플랫폼에 맞게 컴파일을 하려면 시간이 오래 걸린다. 동적 컴파일 환경은 실행 과정에서 컴파일을 할 수 있게 만들어졌다. JIT는 정적 컴파일러 만큼 빠르면서 인터프리터 언어의 빠른 응답속도를 추구하기 위해 사용한다. 바이트코드 컴파일러가 시간이 많이 소요되는 최적화를 미리 해주기 때문에 바이트코드에서 기계어 번역은 훨씬 빠르게 진행될 수 있다. 또한 바이트코드는 이식성이 뛰어나 가상 머신이 설치되어 있으면 빠르게 실행할 수 있다. JIT 코드는 일반적인 인터프러터 언어에 비해 훨씬 좋은 성능을 낸다. 심지어 경우에 따라 정적 컴파일러 언어보다 좋은 성능을 내곤 하는데, 이는 실행 과정에 컴파일을 할 수 있기 때문에 가지는 장점이라고 할 수 있다:

인터프리터(아래 중 적어도 한가지 기능을 가진 프로그램)
1) 소스 코드를 직접실행(실행 중 프로그래밍 언어를 읽어가며 해당 기능에 대응하는 기계어 코드 실행)
2) 소스 코드를 효율적인 다른 중간 코드로 변화하고, 변환한 것을 바로 실행
3) 인터프리터 시스템의 일부인 컴파일러가 만든, 미리 컴파일 된 저장 코드의 실행을 호출
컴파일러 : 고급 명령어들을 직접 기계어로 번역 (실행하기 전에 프로그램 코드를 기계어로 번역)

자바스크립트 작동원리

자바스트립트엔진

자바스크립트 엔진이란?

  • 자바스크립트 코드를 실행하는 프로그램 또는 인터프리터이다
  • 자바스크립트 엔진은 전통적인 인터프리터일 수도 있고, 특정한 방식으로 바이트 코드로 JIT 컴파일 할 수 있다.
  • 여러목적으로 자바스크립트 엔진을 사용하지만, 대체적으로 웹브라우저에서 사용된다.

자바스크립트 엔진 종류

  • 라이노 : 모질라 재단이 운영, 오픈소스, 모두 자바로 개발
  • 스파이더몽키 : 최초의 자바스크립트 엔진, 넷스케이프 내비게이터에서 지원되어 오늘날은 모질라 파이어폭스를 지원
  • V8 : 오픈소스, 덴마크에서 구글이 개발, 구글 크롬의 일부
    - 유일하게 바이트코드와 같은 중간코드를 생산하지 않음
  • 웹킷 : 오픈소스, Nitro가 홍보하고 사파리용으로 애플이 개발
  • KJS : KDE의 ECMAScript/자바스크립트 엔진. 캉커러 웹 브라우저를 위해 KDE 프로젝트의 Harri Porten이 개발
  • 차크라(JScript9) : 인터넷 익스플로러용
  • 차크라(자바스크립트) : 마이크로소프트 엣지용

V8 엔진 동작방식

  • 크롬의 v8엔진은 JIT컴파일에 해당

Process란?

  • 운영체제에서 실행중인 하나의 프로그램
  • 두개이상의 Process는 멀티 프로세스, 그렇게 여러개 일을 동시에 하는 것이 멀티태스킹

thread란?

  • process의 작은 단위
  • thread는 단 한개의 일만 처리 가능
  • thread가 여러개 모여 프로세스라함

메모리 구조

  • 프로그램이 실행되는 동안 CPU가 코드 처리하기 위해서 메모리가 명령어와 데이터들을 저장
    코드(code)영역
  • 실행할 프로그램의 코드가 저장되는 영역
  • 텍스트 영역이라도 부름
  • CPU는 코드 영역에 저장된 명령을 하나씩 가져가서 처리
  • 프로그램이 시작하고 종료될때까지 메모리에 남아있는다
    데이터(data)영역
  • 전역변수와 정적변수(static)가 저장되는 공간
  • 프로그램이 시작하고 종료될때까지 메모리에 남아있는다
    힙(heap)영역
  • 프로그래머가 직접 공간을 할당, 해제하는 메모리공단
  • malloc()또는 new연산자를 통해 메모리를 할당하고 free(), delete연산자를 통해 메모리 해제
  • 선입선출(FIFO, first-in, first-out)방식으로 가장먼저 들어온 데이터가 가장 먼저 인출
    - 힙영역이 메모리의 낮은 주소에서 높은 주소방향으로 할당되기 때문
  • 런타임에 크기가 결정
    스택(stack)영역
  • 프로그램이 자동으로 사용하는 임시 메모리 영역
  • 함수 호출시 생성되는 지역 변수와 매개변수가 저장되는 영역, 함수 호출이 완료되면 사라진다
  • push로 데이터 저장,pop으로 데이터 인출
  • 후입선출(LIFO, last-in, first-out)방식으로 가장 나중에 들어온 데이터가 가장먼저 인출
    - 스택영역이 메모리의 높은주소에서 낮은 주소방향으로 할당
  • 컴파일 타임에 크기가 결정됨
    오버플로우(overflow)
  • 한정된 메모리 공간이 부족하여 메모리 안에 있는 데이터가 넘쳐 흐르는 현상
  • heap오버플로우와 stack 오버플로우가 있음
    - heap이 stack을 침범 -> heap overflow
    • stack이 heap을 침범 -> stack overflow

callStack란?

  • 현재 실행중인 서브루틴(함수)에 대한 정보들을 담아두는 stack구조의 메모리 영역
  • 싱글스레드로 한개씩 처리해야하기 때문에 프로세스 중 어느단계 있는지 기록하게 됨

javascript -> single thread 언어 : 즉 한번에 한개의 일만 처리할 수 있음

function one(){
	two();
}
function two(){
	console.log('Hello World!');
}

one();

one을 실행하게 되면 stack에 다음과 같이 쌓이게 된다.

  • stack구조는 메모리가 높은곳에서부터 낮은곳으로 쌓인다
  • 메모리가 낮은곳에 실행이 먼저 되기 때문에 후입선출(LIFO)방식으로 실행
  • 이렇게 한번에 한개씩 일만 처리되는데 크롬 등 브라우저를 이용할 때 여러가지일은 하는 것처럼 느꼈을 것이다.
  • javascript는 비동기로 작업을 요청하면 브라우저에 내장된 멀티스레드로 이루어진 webAPI에 작업이 인가되어 메인 callstack과 작업이 동시에 이루어진다 (webAPI에서는 callstack에서 불러온 함수중 비동기적 함수의 run함수를 호출하고 이것을 다시 callback queue로 이동시키며 코드 실행은 callstack에서 이루어진다)

			function first() {
                console.log('1');
                second();
                console.log('2');
            }
            function second() {
                console.log('3');
                setTimeout(() => {
                    third();
                    console.log('4');
                }, 3000);
                console.log('5');
            }
            function third() {
                console.log('6');
            }
            first();

위의 함수실행은 다음과 같다.

first()를 부르자마자
console.log('1')실행
second()호출
second()실행후
console.log('3')실행
setTimeout()실행 -> webAPIs로 들어감
비동기 처리로 console.log('5')실행
first()의 console.log('2')실행
setTimeout 3초 지나면
console.log('6')실행
third()호출
third()실행
console.log('4')실행

setTimeout()부분만 보자면




third가 넘어가서 console.log('6')이 실행되고 third()가 끝나면 second()에서 console.log('4')를 실행한다

			function second() {
                console.log('3');
                setTimeout(() => {
                    third();
                 	console.log('4');
                }, 3000);
                console.log('5');
            }

web APIs

  • 자바스크립트 엔진이 아니라 브라우저에서 제공하는 API
  • 콜스택에서 불러온 함수중 비동기적 함수이면 webAPI가 이것의 run함수를 호출한다
  • web API에서 처리가 끝나면 callback queue로 이동시킴

callback queue(event queue, task queue)

  • web api에서 보내진 함수들이 모이는 곳으로 선입선출(FIFO first-in, first-out)형태
  • event loop의 감시를 받음

event loop

  • callstack과 callback queue를 감시
  • callstack을 감시하다 비게되면 callback queue에 쌓이 함수를 callstack으로 보내주는 역할
    - 이러한 행동을 tick이라고함
    • event loop를 통해 동기함수와 비동기 함수의 순서가 정해짐

비동기/동기 블로킹/논블로킹을 비교하려다 여기까지왔다.. 정작 비교는 못했지만 자바스크립트 동작원리를 정리할 수 있어서 너무 뿌듯하다.
다른블로드글에 글이 너무 잘써져있어서 이해하면서 새롭게 작성한부분도 동일한 부분도 있는데 혹시 틀린부분이 있으면 언제든지 댓글로 이야기 해주시면 감사하겠습니다. 내일은 비교를 꼭 해보자..!

0개의 댓글