자바스크립트에서는 참조 타입에 따라 메모리가 할당되는 방법이 다르다. 참조타입에는 원시 타입, 객체 타입으로 나뉘며 두 타입에 대해 메모리가 어떻게 할당되는지 살펴보자.
원시 타입 : 기본적인 타입 (Number, String, Boolean, Undefined, Null, Binint... 등)
객체 타입 : function, object, array ... 등
원시 타입의 값을 변수에 할당하게되면, 변수는 실제 값이 스택 영역에 저장된다.
let v1 = 126;
let v2 = variable;
참조 | 스택 영역 | 메모리 주소 |
---|---|---|
v1 | 126 | 0x0004 |
v2 | 126 | 0x0008 |
원시타입은 변경 불가능한 값으로 재할당을 하게 된다면 기존 메모리가 아닌 새로운 메모리 공간을 확보하고 그 공간에 실제 값이 저장된다.
let v1 = 126;
let v2 = variable;
v1 = v2 + 1;
v2 = 300;
참조 | 스택 영역 | 메모리 주소 |
---|---|---|
회수 | 126 | 0x0004 |
회수 | 126 | 0x0008 |
v1 | 127 | 0x0012 |
v2 | 300 | 0x0016 |
v1, v2가 새로운 메모리 공간에서 재할당 되고 기존에 사용하던 메모리는 아무런 변수가 참조하고 있지 않다. 이때 가비지 콜렉터(Garbage Collector)가 이 메모리를 회수해가며 메모리가 관리되는 것이다.
자바스크립트에서 Heap은 원시 타입이 아닌 데이터를 저장하는 공간이다. 즉 객체, 배열, 함수 등과 같은 복잡한 타입의 데이터가 힙에 저장된다.
참조 타입은 힙 메모리에 실제 데이터가 저장되며 스택영역에는 힙 메모리에 저장된 메모리 주소를 저장하게 되고 스택 영역의 저장된 주소 값을 통해 힙 영역의 참조 타입의 데이터에 접근할 수 있다.
const obj = {
key : "value";
}
참조 | 스택 영역 | 메모리 주소 |
---|---|---|
obj | 0x0008 | 0x0004 |
메모리 주소 | 힙 영역 |
---|---|
0x0008 | { key : "value" } |
객체를 복제하는 경우 서로 같은 힙 영역의 메모리 주소를 가르키게 된다.
const obj1 = {
key : "value";
}
const obj2 = obj1;
참조 | 스택 영역 | 메모리 주소 |
---|---|---|
obj1 | 0x0012 | 0x0004 |
obj2 | 0x0012 | 0x0008 |
메모리 주소 | 힙 영역 |
---|---|
0x0012 | { key : "value" } |
obj1과 obj2가 같은 객체를 가리키고 있기 때문에 obj2를 수정할 경우 obj1에도 같이 데이터가 수정된다. 이 처럼 객체가 저장된 주소를 복제하는 것을 얕은 복사(Shallow Copy)라 하며 힙 메모리의 객체 데이터를 복사하고 싶다면 깊은 복사(Deep Copy)를 해야한다.
자바스크립트에서는 배열과 객체를 상수(const)로 선언해도 요소를 변경할 수 있다. 상수는 변하지 않는 고정 값인데 왜 이게 가능할까?
Heap에서 메모리 영역은 동적으로 크기가 변할 수 있다. 이러한 이유로 배열, 객체를 const로 선언한 후에 요소를 변경해도 동작하는 이유다.