본문 바로가기

Deep Dive

[JavaScript] String의 이중성 (원시 / 객체 타입 사이)

 

 

 

기본적으로 Javascript에서 String은 원시 타입이지만, heap 영역에 저장된다는 이야기를 들었다.

원시 타입이면 Stack 영역에 저장되어야 하는 것 아닌가..? 그때부터 String에 대한 혼란이 가중되었고, 이 부분에 대해 찾아보았다. 

 

 


 

✏️ 원시 타입으로서의 String

 

자바스크립트의 명세상 String(문자열)은 원시 타입이 맞다.

원시 타입의 특성상, 불변성(Immutability)을 가지며 값에 의한 전달(Call by Value)이 이루어진다.

 

내가 알고 있던 기본 정보는,

원시 타입은 값으로 저장되기 때문에 Stack 영역에 저장되고, 객체 타입은 변동 가능성 때문에 heap 영역에 저장되어 메모리 주소로 참조하는 것이었는데.

 

그런데 어떻게 문자열은 원시 타입인데, heap 영역에 저장된다는 것일까?

 

 

 

✏️ String의 이중성

String은 이중성을 가지고 있다. 정말 아수라백작 같은 놈이다.

 

원시 타입으로 취급되지만, 객체처럼 메서드와 프로퍼티를 가질 수 있다.

이는 문자열에 메서드나 프로퍼티 접근이 필요할 때 JavaScript 엔진이 일시적으로 String 객체(래퍼 객체)를 생성하기 때문이다.

 

그래서 문자열이 원시 타입임에도 불구하고, 아래와 같이 메서드와 프로퍼티를 가질 수 있는 것이다.

 

let str = "Hello";
console.log(str.length); // 5
console.log(str.toUpperCase()); // "HELLO"

 

 

 

 

✏️ Constant Pool과 문자열

(이 부분에 대해서 나중에 또 포스팅할 예정이라 간단히 설명하자면) V8 엔진은 성능 최적화를 위해 Constant Pool을 사용한다. 

Constant Pool은 문자열 리터럴을 저장하고 관리하는 메모리 영역으로, 동일한 문자열이 여러 번 사용될 때 중복 저장을 방지한다.

 

예를 들어,

let str1 = "hello";
let str2 = "hello";

 

이렇게 같은 내용의 문자열은, Constant Pool에서 동일한 위치를 참조하는 것을 아래 이미지에서 확인할 수 있다. 

 

 

 

 

 

✏️ Constant Pool의 문자열 저장 방식

 

실제로 디버깅 해보니, 문자열 저장 방식에 대해 좀 더 정확히 알 수 있었다.

우선 나는 영문/한글로 디버깅 해봤는데, 이후에 알게 된 정보들은 아래와 같다.

 


 

1. 모든 문자열이 heap의 OldSpace에 저장된다. heap 영역에 저장되는 것이 맞았다. 

 

2. INTERNALIZED_STRING_TYPE으로 타입을 관리하는데, 영문과 한글이 조금 다르다.

    > 영문 : ONE_BYTE_INTERNALIZED_STRING_TYPE

    > 한글 : INTERNALIZED_STRING_TYPE                            # 한글은 2byte 문자이기 때문

 

3. 영문/한글에 따라 인코딩 타입이 다르다. (한글은 유니코드 인코딩 사용)

영문
한글

 

 

4. 글자수가 적건, 많건 글자수는 저장 방식에 아무런 영향을 미치지 않는다.

 

 


 

 


 

 

 

✨ 정리하자면...

 

문자열은 개념적으로는 원시 타입이지만, 문자열의 특성 때문에 heap 영역에 저장된다.

문자열은 언제든지 길이가 늘어날 수 있기 때문에, 동적으로 크기 조절이 가능한 heap 영역에 저장해야 하는 것이 좋다.

 

V8 엔진은 이러한 문자열의 특성을 알기 때문에, 문자열의 길이가 어떻든 Constant Pool의 heap 영역에 문자열을 저장해두는 것이다.

또한 heap 영역은 가비지 컬렉션을 통한 효율적인 메모리 관리가 가능하다.

 

내가 알고 있던 '원시 타입은 stack 영역에 저장된다'는 공식이 절대적이지 않음을 이번 기회로 한 번 더 배웠다. 

원시 타입 or 객체 타입은 값의 취급 방식에 대한 구분이고, stack or heap 영역은 메모리 관리 방식에 대한 구분이라 다른 개념이며,

자바스크립트 엔진은 효율성을 위해 내가 알고 있는 개념과 다르게 동작하기도 한다. 

 

개발자는 보통 string을 원시 타입으로 다루지만, 엔진은 내부적으로 최적화된 방식으로 처리하기 때문에 해당 개념에 오류가 발생할 수 있음을 인지하고 사용하면 좋을 것 같고, 이러한 부분을 알아두면 나중에 디버깅 시 많은 도움이 될 것 같다.