자바스크립트 동작 원리(Stack, Queue, Heap)

JINSUNG LEE·2022년 1월 18일
2
post-thumbnail



프론트엔드 개발자들이 작업을 하면서 자바스크립트는 땔래야 땔 수가 없는 프로그래밍 언어이다.

그런데 막상 자바스크립트를 사용하면서 작동 원리에 대해 제대로 파악하지 못한 관계로

이번 시간에는 자바스크립트의 작동 원리에 대해 소개한다.




자바스크립트의 작동 내부 구조

우선 동작원리에 대해 알기 위해서는 내부 구조가 어떻게 되어 있는지부터 파악하는게 좋다.

자바스크립트의 동작 내부 구조는 위와 같이 Memory Heap, Call Stack, Callback Queue로 구축 되어있다.

위 구조는 구글의 V8 Engine의 대표적 구조이다.

Memory Heap


const obj = {a: "123"};

let arr = [1, 3, 5];

let arr2 = ["a", "b", "c"];

코드 상 변수를 선언 및 할당하여 바인딩하면 Memory Heap은 위와 같은 그림처럼 저장되어 있다.

즉, Memory Heap은 각 변수들의 참조형 데이터(함수, 객체, 배열)들의 메모리 주소와 값들이 저장되어 있다.

Call Stack 의 참조 데이터 값(Value)들은 주소로 저장되어 있으며, 해당 주소들을 통해 Memory Heap의 주소와 맞으면 값들을 조회할 수 있게 된다.

반면 원시형 데이터들은 Call Stack에서 그대로 값들이 저장되어 있으므로 Memory Heap까지 탐색할 필요가 전혀 없다.

이를 통해 예전에 배웠던 얇은 복사와 깊은 복사의 차이가 Memory Heap, Call Stack과 깊게 연관되어 있다는 것을 다시 알 수 있다.

Call Stack


let a = 1
console.log(1)
setTimeout(() => {
    console.log(2)
}, 0)
console.log(3)

Call Stack실행할 수 있는 코드를 계산 및 모든 변수들의 집합체들이 모여 있으며 처리 방식은 LIFO(Last In First Out)로 공간 요소들이 순차 처리된다.

그러나 참조형 데이터들은 극단적으로 수 만가지 데이터를 저장한다면 Call Stack이 관리하기 한계가 있어 주소만 저장한 채 앞서 설명한 Memory Heap에 제대로된 값들이 저장 되었던 것이다.

또한, Call Stack은 자바스크립트의 메인 역할에 해당되며 단 하나만 존재하는데 이를 통해
자바스크립트는 싱글 스레드 기반의 언어라는 것을 제대로 증명할 수 있게 된다.

싱글 스레드 기반의 언어이므로 위 코드의 출력 결과는 1 2 3이 출력이 될줄 알겠지만,

결과는 1 3 2이 출력된다.

분명 싱글 쓰레드 기반이라 1 2 3이 출력되어야 하는거 아닌지 혼란에 빠질 수도 있다.

			 				마!! 니 싱글 쓰레드인데 내랑 지금 장난치나??? 

사실 해당 출력결과가 나온 이유에는 CallBack Queue 때문이다.

CallBack Queue

CallBack Queue는 일종의 대기실 같은 공간과 비슷한 역할을 수행한다.

해당 대기실에 들어가는 경우는 Web API 3가지로 구성되어 있다.

  1. setTimeOut
  2. AJAX 요청
  3. requestAnimationFrame

위와 같은 키워드를 사용하면 queue에 담겨줘 있으며, 만일 Call Stack에 존재하던 모든 요소들이 처리가 다 완료 됐을 시 queue는 FIFO(First In First Out) 방식으로 처리가 된다.

즉 이러한 과정들은 Event Loop를 통해 처리가 되며, Event Loop를 쉽게 요약하자면 태스크가 들어오기까지 잠들어 있다가 태스크가 들어오면(queue) 이를 처리하고(stack으로 전달), 처리할 태스크가 없는 경우엔 다시 잠이드는, 끊임없이 돌아가는 자바스크립트 내 Loop이다.

그렇다면 자바스크립트는 Web API로 인해 싱글 스레드가 아닌 비동기 처럼 수행되기도 하는 프로그래밍 언어이다.

자바스크립트는 위와 같은 특징 덕분에 자바스크립트 런타임 환경에 맞춰 탄생한 Node.js 플랫폼을 통해 서버까지 다룰 수 있게 된다.

가비지 컬랙터 (GC)

그렇다면 메모리 공간(Call Stack,Memory Heap) 들은 언제 쯤 제거가 될 지 궁금할 수도 있을 것이다.

더 이상 참조되지 않는 데이터들은 자연스레 소멸 되는데 예시는 아래와 같은 상황에 가비지 컬랙터가 발동된다.

let arr = 10
let arr2 = 20

arr = 20

변수 arr을 20이라는 값으로 재할당될 경우, 값이 변경되는 것이 아닌 arr2의 변수가 있는 메모리 주소를 동일하게 공유하여 20이라는 값을 갖게 된다. 더 이상 10이라는 값은 어느 변수에도 선언되지 않은 관계로 10이라는 값이 저장된 메모리 주소는 제거가 되며 이 과정에서 가비지 컬랙터가 작동한다.

이를 통해 주소와 값들이 자동적으로 제거가 되며, 메모리를 더욱 가볍게 관리한다.

물론 C/C++ 같은 언어 프로그래밍들은 별도로 가비지 컬랙터를 지정해주어야 메모리 관리를 해주지만, 자바스크립트는 편하게도 함수 실행이 종료되면 자동적으로 메모리를 가비지 컬랙터로 관리를 해준다.

그러나 개발자들은 절대적으로 자바스크립트의 가비지 컬랙터를 신뢰해서는 안된다.


let arr = []
    
while(true) {
   arr.push(1)
}

위와 같은 무한 루프에 빠지게 되면 함수를 여전히 실행되며, 메모리 제한 공간을 넘어서 계속 저장되는메모리 누수가 발생하므로 코드를 작성 시 메모리 관리에 대해 신중하게 생각하며 작성하여야 한다.

profile
https://californialuv.github.io/Tech_Blog 이사 갔어용 🌎 🚀

0개의 댓글