WEB/💡 Javascript

JavaScript에도 String Pool이 있을까? - V8의 String Table 알아보기

무딘붓 2024. 11. 9. 16:50

 

 

📝 1. 서론

`let a = 'abc'; let b = 'abc'` 일 때, a와 b는 같은 주소를 참조하나요?

 

 

스터디에서 JavaScript의 string 타입을 이야기하던 날, 위와 같은 질문을 받았습니다. Java에서는 스트링 풀(String Pool)을 이용해서 동일한 문자열을 재사용하는데, JavaScript에서도 비슷한 개념이 있는지를 묻는 질문이었습니다.

 

위 질문에 대한 답을 찾는 과정이 이번 글의 주제입니다.

 

미리 정답부터 말하자면, ‘그렇다’ 입니다. V8 엔진에서는 String Table 구조를 이용하여 동일한 문자열을 한 번만 저장하는 최적화가 이루어집니다. 이 글에서는 먼저 V8 엔진을 사용하는 환경에서 동일한 문자열을 가지는 두 변수가 실제로 같은 주소를 참조하는지 확인하고, V8 엔진이 동일한 문자열을 어떻게 관리하는지 살펴보겠습니다.

 


 

🔍 2. 메모리 주소 확인해 보기

 

JavaScript에서 동일한 문자열을 할당한 두 변수가 같은 주소를 참조하는지 직접 확인해 보겠습니다.

이를 위해 V8 엔진을 사용하는 Node.jsChrome에서의 확인 방법을 소개합니다.

 

Node.js - V8 내부 메서드 %DebugPrint 사용

 

Node.js에서는 V8의 `%DebugPrint`라는 내부 메서드를 사용하여 변수의 메모리 주소를 확인할 수 있습니다. 이 메서드를 실행하려면, Node.js를 `--allow-natives-syntax` 플래그와 함께 실행해야 합니다.

 

아래 코드를 실행해 두 변수가 같은 주소를 참조하는지 확인해 보겠습니다

let a = 'abc';
let b = 'abc';
let c = 'abcd';

%DebugPrint(a);
%DebugPrint(b);
%DebugPrint(c);

 

위 코드를 실행한 결과는 다음과 같습니다.

실행 결과 콘솔창

 

출력 결과를 보면, 변수 `a`와 `b`가 동일한 메모리 주소 `00000098A0809359`를 참조하고 있습니다.
즉, 문자열 ‘abc’는 한 번만 저장되며, `a`와 `b`는 같은 주소를 공유합니다.
비교를 위해 확인한 `let c = 'abcd';` 는 다른 주소를 가지고 있습니다.

 

Chrome - 개발자 도구 Heap Snapshot 활용

 

Chrome 개발자 도구에서는 실제 메모리 주소를 확인할 수 없지만, 메모리 탭의 Heap Snapshot(힙 스냅샷) 기능을 사용해 동일한 문자열이 어떻게 저장되는지 확인할 수 있습니다.

 

아래와 같은 코드를 먼저 실행해 보겠습니다.

let a = '안녕하세요';
let b = '안녕하세요';
let c = '안녕!';

 

 

위와 같이 코드를 실행시킨 후, ‘안녕하세요’를 검색한 결과, String ‘안녕하세요’는 단 하나만 존재하고 있습니다.

 

 

다른 방식으로 확인할 수도 있습니다.

아래 코드를 실행 후, 힙 스냅샷을 확인해 보겠습니다.

let obj1 = { a : '안녕하세요', b : 'object1'};
let obj2 = { x : '안녕하세요', y : 'object2'};

 

 

`obj1` 의 `a` 와 `obj2` 의 `x` 가 같은 주소를 참조하고 있습니다.

 

 


 

🗂️ 3. V8은 같은 문자열을 어떻게 관리하는가? - String Table

 

그렇다면 V8 엔진에서는 같은 문자열을 어떻게 한 번만 저장하고 재사용할 수 있을까요? 이를 이해하기 위해 먼저 String Interning 개념을 알아보겠습니다.

 

 

String Interning 개념 이해하기

 

String Interning동일한 문자열을 메모리에 한 번만 저장하는 기법입니다. 같은 문자열을 여러 번 사용할 때, 동일한 메모리 주소를 참조하기 때문에 메모리 사용량을 줄이고, 문자열 비교를 빠르게 할 수 있다는 장점이 있습니다.

 

대표적으로 Java는 String Pool을 사용해 String Interning을 수행하며, `intern()` 메서드를 사용해 수동으로 문자열을 String Pool에 추가할 수 있습니다. Python은 짧은 문자열을 자동으로 intern(재사용)하며, 긴 문자열은 `sys.intern()`을 사용해 수동으로 intern할 수 있습니다.

 

JavaScript는 명시적으로 String Pool을 관리하지는 않지만, JavaScript 엔진들은 비슷한 메커니즘을 사용하고 있습니다. 대표적인 JavaScript 엔진인 V8에서는 어떻게 문자열을 관리하는지 알아보겠습니다.

 

 

V8 엔진의 String Table

 

V8 엔진은 문자열을 해시 테이블 구조로 관리하는 String Table을 사용합니다. 새로운 문자열이 생성되면 이 해시 테이블에서 중복을 확인하고, 이미 존재하는 문자열이 있다면 기존 문자열 객체를 참조하게 합니다. 다른 언어와 달리 명시적 intern 기능은 없습니다.

 

새로운 문자열이 생성될 때, String Table에서 일어나는 일을 간단히 요약하면 다음과 같습니다.

  1. 문자열 해시 값을 생성
  2. 해시 값이 String Table에 존재하는지 확인
  3. 문자열이 테이블에 존재하면
    • 기존 문자열을 안전하게 참조할 수 있는 핸들 `DirectHandle<String>` 을 반환.
  4. 문자열이 테이블에 존재하지 않으면
    • 문자열을 힙에 저장한 후, String Table에 추가
    • 새 문자열을 안전하게 참조할 수 있는 핸들 `DirectHandle<String>` 을 반환.

 

자세한 구현 과정은 V8 GitHub 소스코드에서 알아볼 수 있습니다.

 

 

다른 엔진에서는?

 

다른 JavaScript 엔진들도 V8과 유사한 방식으로 문자열을 관리합니다. JavaScriptCore 엔진에서는 Identifier 클래스를 이용해서, SpiderMonkey 엔진에서는 JSAtom 구조로 동일한 문자열을 하나만 저장하여 재사용하고 있습니다.

 

 

 


 

🌟 4. 결론 요약

 

JavaScript에서도 Java나 Python처럼 동일한 문자열을 메모리에 한 번만 저장하는 String Interning 개념을 사용합니다.

 

대표적으로 V8 엔진에서는 String Table을 활용해 동일한 문자열을 한 번만 저장하며, 이를 통해 메모리 사용량을 줄이고 문자열 비교를 빠르게 수행할 수 있습니다.

 


 

📚 5. 참고자료

 

https://blog.frontend-almanac.com/v8-strings

 

V8. Working with Strings. Expanding Vocabulary

What is a string? What types of strings exist? How are they stored inside the engine? Let\'s examine all the details and features in depth.

blog.frontend-almanac.com

 

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

 

How are strings stored in JavaScript ? - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

https://yceffort.kr/2022/04/how-javascript-variable-works-in-memory

 

V8에서 관리되는 자바스크립트 변수

Table of Contents 거의 대부분의 변수는 힙에 존재한다. 일반적으로 원시값은 스택에, 객체는 힙에 할당된다고 알려져있지만, 이와 반대로 자바스크립트의 모든 원시값도 힙에 할당되어 있다. 이는

yceffort.kr

 

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

 

V8 Engine의 integer, string이 메모리 어디에 할당 되는가?

JavaScript는 debug하기가 어렵습니다. 때문에 node에서 컴파일러로 사용되는 V8 engine의 docs를 보거나, 여러 사람들이 작성한 Reference를 봐야합니다. 책 JavaScript Deep Dive에서 간략하게 JavaScript메모리에

hwan-shell.tistory.com