내가 혼자 공부하는 컴퓨터 + 운영체제 책을 완독한 이유(부제:v8)

·2024년 2월 10일
16
post-thumbnail

사건의 발단

작년 여름이었습니다. v8히든 클래스 글을 작성하기 위해 네트워크 탭에서 여러가지 실험을 해보다 원시값이 (정확히는 문자열이) 힙 메모리에 나타나는 것을 보고 "대체 뭐지..?" 라는 의문을 가지게 되었습니다.

function Student(string, number, smi) {
    this.string = string; // string
    this.number = number;  // number
    this.smi = smi; // smi : 32비트 이하의 정수
}
const Jim = new Student('nameTest', 1.2, 5 )

( 스냅샷을 직접 찍어보고 싶으신 분들은 해당글을 확인해주세요. )

그때부터 저는 v8에서 원시값은 정말 스택에 저장되는게 맞는가? 라는 궁금증이 시작됐습니다. 그래서 문서를 좀 더 찾아보니 실제로 v8에서는 대부분의 값이 힙에 저장된다고 하더라구요.

JavaScript values in V8 are represented as objects and allocated on the V8 heap, no matter if they are objects, arrays, numbers or strings. This allows us to represent any value as a pointer to an object. (* https://v8.dev/blog/pointer-compression)

이 때문에 작성했던 글이 원시 데이터는 V8 엔진에서 메모리에 어떻게 저장될까요? 입니다.

smi

근데 또 smi 라는 개념이 있다네요. 요게 뭐냐면 32비트 이하의 정수입니다.
그래서 이건 또 stack 에 저장되냐 힙에 저장되냐... 확실한 결론이 나질 않아 계속해서 문서를 읽어봤었는데 직접적으로 메모리에 할당된다는 말밖에 없었으며 스택에 저장된다는 말 또한 없었습니다.

그래서 다음 궁금함 STEP.. "힙에 저장이 안된다고 쳐도, 그렇다면 smi는 스택에 저장되는게 맞긴 한가?" 라는 의문이 들더라구요.

v8 깃허브

https://github.com/v8/v8/blob/main/src/objects/objects.h

Smi represents integer Numbers that can be stored in 31 bits.
Smis are immediate which means they are NOT allocated in the heap.

좀 더 자료를 찾아보니 v8레포에 주석으로 smi는 힙에 할당되지 않는다고 명시되어 있었습니다.

왜 smi 는 stack 에 저장되는가

저는 이 글을 읽고 비로소 이해했습니다.

  • 스택은 미리 자료형의 크기를 알고 있을때 적합합니다.

  • 자바스크립트는 동적언어입니다. 즉, 실행하기 전까지는 어떤 변수의 자료형인지 미리 할 수 없습니다.

  • 그래서 기본 전략이 "모두 힙에 할당한다." 입니다.

  • 스택에는 힙에 할당된 값들을 가리키는 "포인터"만 있습니다. 64비트 환경을 기준으로 64비트짜리 포인터입니다.

  • 64비트는 고정된 크기스택에 박을 수 있습니다. 그런데, 꼭 포인터에 64 비트가 다 필요할까요?

  • v8은 포인터를 저장할때 마지막 비트를 1로 바꿔서 저장합니다. (최소 홀수인 메모리 주소를 갖는 값은 없기 때문) 이를 통해 마지막 비트가 1임을 확인하고 "이건 포인터구나" 라고 판단합니다.

  • v8은 32비트 정수(smi) 를 저장해야 할 때마다 포인터 대신에 그 수를 직접적으로 바로 저장합니다.

  • 64비트 공간중에 아래 32비트는 0으로 하고 위 32비트는 원하는 정수를 적습니다.

  • 포인터 공간에 다른 값을 같이 담는 tagged pointer의 일종입니다.

이해한 것을 다시 한 번 정리해보자면

일단 스택에는 값이 고정되어 있는 것들을 담기 유리한 자료 구조입니다. 그래서 스택에는 힙에 저장되는 주소값을 가진 포인터만 존재합니다. 그 포인터(주소)의 크기는 64비트입니다. v8은 이 마지막 비트를 1로 바꿔서 저장합니다. 그럼 연산할때마다 마지막 비트가 1임을 확인하고 "이건 포인터구나" 하고 인지합니다. 근데 smi라고 32비트 이하 정수는 굳이 64비트보다 작기때문에 굳이 힙에 저장할 필요 없습니다. 그래서 그 값을 직접적으로 스택에 저장합니다. smi는 64비트중에 32비트는 0으로 하고 위에 32비트에 원하는 정수를 적습니다. 그럼 포인터 뒷자리는 1인데 smi는 0이기 때문에 포인터랑 smi랑 구분이 되겠죠?

smi

저도 현재까지도 공부중이기 때문에 완벽히 맞다고 100% 보장드릴 수 없습니다.
혹시 정정하고 싶은 지식들이 있으면 댓글 남겨주세요!

그 후에 생긴 궁금

"스택 포인터란 뭘까?"

"tagged pointer가 뭐지?"

"왜 메모리 할당을 이렇게까지 해서 아껴야하는거지..?"

저는 이때를 기점으로 컴퓨터 구조나 운영체제를 공부해야겠다고 생각이 들었습니다. v8 문서를 읽는데 번역기를 아무리 돌려보아도 잘 이해가 가지 않았습니다. 물론 제 영어 원문 해석 능력 부족이 문제일 수도 있습니다. 하지만 끝내 저의 컴퓨터 관련 기본 지식이 부족하기 때문에 더 심도있는 학습으로 넘어갈 시에 큰 어려움을 느낀다는 결론을 내렸습니다.

연휴 기간을 이용하여 이틀에 걸쳐 책을 가볍게 완독을 하고 간단하게 공부한 내용을 정리를 하면서야 비소로 기본 개념들을 인지할 수 있게 됐습니다. 재밌는 내용들이 많아 밤을 새워 몰입해서 읽었습니다. 아직 개념들이 완벽하게 숙지가 된 것은 아니지만 이제는 여러가지 용어들이 생소하지만은 않게 느껴져서 좋습니다. 다시 모르는 개념들이 나올때 배웠던 용어들을 한번 더 상기해본다면 더 좋을 것 같습니다. 다만 책을 완독하고 다시 V8문서를 읽어보아도 여전히 본문 내용은 어렵더군요...

이렇게 내가 혼자공부하는컴퓨터 + 운영체제 책을 완독한 이유 글을 마칩니다. 이유가 약간 싱겁죠? 결국 v8로 시작했다 v8로 끝나버리는... 😂

이 내용을 몰라도 당장 개발을 하는데 지장은 없습니다. 하지만 너무 흥미롭고 재밌지 않나요? 우리는 단순히 원시값은 스택, 참조값은 힙에 저장된다고 배웠는데 사실은 그 안에도 수 많은 숨은 지식들이 있었다는게...!

궁금했던 것들이 해결 됐습니다. 저는 단순히 "v8에서 smi는 스택에 저장된다." 라는 결론이 궁금했던 것이 아닙니다. "v8에서 smi는 어떤 이유로 스택에 저장되는가." 가 궁금했습니다.그리고 이번 기회를 통해 앞으로의 궁금증을 해결하기 위해서는 개인 시간에 '저를 위해서라도' 더 열심히 공부해야겠다는 결심이 섰습니다.

그럼 모두 즐거운 연휴 보내세요!

profile
My Island

1개의 댓글

comment-user-thumbnail
2024년 2월 12일

여름 밤의 추억..

답글 달기