원시 데이터는 V8 엔진에서 메모리에 어떻게 저장될까요?

·2023년 8월 21일
12

프론트엔드

목록 보기
5/10
post-thumbnail

자바스크립트의 타입

자바스크립트의 원시 타입에는 아래와 같이 여섯 가지가 있으며, 이 외의 모든 값은 객체(참조) 타입입니다.

📂 숫자(Number, BigInt)
📂 불리언(Boolean)
📂 null
📂 undefined
📂 문자열(String)
📂 Symbol

우리는 흔히 자바스크립트 원시 타입은 stack, 참조 타입은 heap에 저장되는 것으로 알고 있을 것입니다. 하지만 조금 더 깊게 들어가보면 그 안에 조금 더 복잡한 과정들이 숨어있습니다. 오늘은 특별히 V8엔진에서 Number 타입과 String 타입이 식별자에 할당되는 과정을 자세히 알아보려 합니다.

🔉 해당 글을 읽기 전 원시데이터, 참조 데이터가 식별자에 할당되는 과정을 이해한 뒤 보시면 더 좋습니다.

1. Number Type

Integer는 기본적으로 V8 engine의 stack pointer에 저장됩니다.

32비트 플랫폼에서 포인터가 아닌 -230~230-1 범위의 정수값, 즉 31비트 부호있는 정수값이 직접 저장됩니다. 이에 해당하는 정수 값을 V8 엔진에서는 SMI(Small Integer)라고 별도로 구분하여 지칭합니다.

이렇게 크기에 따라 저장 공간을 나누는 이유는 무엇일까요 ? 정수의 경우에는 사용 빈도가 너무 높기 때문에 동일한 방식으로 관리가 이루어진다면 값이 변경되거나 계산이 수행될 때마다 매번 새로운 개체를 할당해야 하는데 이는 너무 큰 부담이기 때문입니다.

실험코드

function test1() {
  let a = 123123123123;
}

function test2() {
  let c = 9876;
}

function test3() {
  let c = 1.1;
}

test1();
test2();
test3();

명령어 입력

 node --print-bytecode --print-bytecode-filter=test* 폴더이름

📊 test 1 결과


Number가 32Bit를 넘어서서 Heap에 할당됐습니다.

📊 test 2 결과

test2 결과는 Constant pool에도 등록이 안되었으며 Heap에 등록된 내용 또한 없습니다.

📊 test 3 결과

정수가 아닌 실수 또한 Heap에 저장됩니다.

여기서 결과를 보면 알 수 있다시피 무조건 큰 숫자라고 해서 Heap 메모리에 저장 되는 것이 아닙니다. smi 형식에 맞지 않는 Number 값들이 Heap 에 저장 될 뿐입니다.

Numbers can be stored as either:
an immediate 31-bit integer values called small integers (SMIs), or
heap objects, referred to as heap numbers. Heap numbers are used for storing values that do not fit into the SMI form, such as doubles, or when a value needs to be boxed, such as setting properties on it.

*https://developer.chrome.com/docs/devtools/memory-problems/memory-101/

2. String Type

동시에 문자열을 효율적으로 처리하기 위해 V8 엔진은 문자열 Constant Pool 을 유지합니다. 문자열은 Constant Pool에 저장됩니다. 실제로 V8 엔진뿐만 아니라 Java 가상 머신과 같은 많은 인터프리터에서도 문자열 Constant Pool 을 유지합니다.

Constant pools are used to store heap objects that are referenced as constants in generated bytecode.
*Constant pools은 생성된 바이트코드에서 상수로 참조되는 힙 객체를 저장하는 데 사용됩니다.

첫 번째 예시

const name1 = '자바스크립트'
const name2 = new String('자바스크립트')

  • 리터럴을 사용하여 문자열을 만들 때 ➡️ name1 처럼 리터럴로 생성된 스트링은 직접적으로 constant pool 가리키는 것을 볼 수 있습니다.
  • new 키워드를 사용하여 문자열을 생성 할 때 ➡️ 항상 힙 메모리에 새 인스턴스가 생성되고 그 값은 String Constant Pool에 저장됩니다.

두 번째 예시

let name1 = '자바스크립트'
let name2 = new String('자바스크립트')
let name3 = '자바스크립트'
let name4 = new String('자바스크립트')

(우리 손가락으로 하나하나 짚어보며 차근차근 따라가보아요.😎)

다시 한 번 서열정리(?) 를 해봤습니다. 조금 복잡 할 수도 있지만 하나씩 따라가다보면 재밌는 사실을 알 수 있습니다. 여기서 발견 할 수 있는 재밌는 사실은 name1과 name3이 같은 포인터를 가리킨다는 것입니다. 이러한 방식으로 문자열 Constant Pool은 동일한 값 문자열이 메모리의 동일한 위치를 가리키도록 하여 메모리를 절약합니다.

세 번째 예시

const name1 = "자바스크립트";
const name2 = new String("자바스크립트");
console.log(a);
console.log(b);

console.log(a == b); //true
console.log(a === b); //false

해당 결과로 new 키워드로 생성한 문자열과 리터럴로 생성한 문자열은 메모리에서 서로 다른 위치를 참조하고 있음을 알 수 있습니다.

레퍼런스

https://www.geeksforgeeks.org/how-are-strings-stored-in-javascript/

https://medium.com/@nourhansaed6/what-is-string-constant-pool-in-js-1b1795f7624b

https://hwan-shell.tistory.com/367

https://levelup.gitconnected.com/bytefish-vs-new-string-bytefish-what-is-the-difference-a795f6a7a08b

profile
My Island

2개의 댓글

comment-user-thumbnail
2023년 8월 21일

매번 이렇게 자세한 내용 포스팅 해주셔서 감사해요!! Number나 String이 Heap에도 저장될 수도 있다니 새로운 사실을 배웟네여,, 잘 배워갑니다!!

1개의 답글