본문 바로가기
JavaScript

데이터 타입 심화, 메모리

by junvely 2023. 4. 4.

데이터 타입 종류

기본형과 참조형을 나누는 기준 : 값의 저장 방식불변성 여부에 따라 나뉜다.

💡 [기본형과 참조형의 구분 기준]

복제의 방식
기본형 : 값이 담긴 주소값을 바로 복제
참조형 : 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주소값을 복제

불변성의 여부
기본형 : 불변성을 띔 => var나 let은 값이 변경되는데? => 메모리 관점에서 봐야 불변한지 아닌지 파악 가능
참조형 : 불변성을 띄지 않음

자, “불변성을 띈다” 이 말을 이해하기 위해서 우리는 메모리와 데이터에 대한 내용을 이해해야만 합니다. 아래에서 그 배경지식을 낱낱이 살펴보기로 합시다 😎

 

 

메모리와 데이터에 관한 배경지식

1. 메모리, 데이터

1)비트

컴퓨터가 이해할 수 있는 가장 작은 단위죠

0과 1을 가지고 있는 메모리를 구성하기 위한 작은 조각을 의미한다고 보면 될 것 같아요!

이 작은 조각들이 모여서 여러분들이 흔히 들으시는 **‘메모리’**가 만들어지는 것이죠.

 

2)바이트

0과 1만 표현하는 비트를 모두 찾기는 부담

1개 → 2개 → … → 8개(새로운 단위 : byte)

 

 3) 메모리(memo + ry) : byte 단위로 구성 => 기본적으로 자바스크립트에서 정수는 8바이트다. => 메모리 조각에 8개의 자리를 차지하는 식으로 메모리에 쌓이게 된다.

 

2. 모든 데이터는 byte 단위의 식별자인 메모리 주소값을 통해서 서로 구분이 됩니다.

💡기본적으로 자바스크립트에서 정수는 8바이트다. 8바이트 = 64비트
만일, 64비트(8바이트) 정수는 메모리에 어떻게 저장할 수 있을까요? ⇒ 64비트를 8개의 바이트로 분할하고, 각 바이트를 메모리에 저장해야 해요. 각 바이트는 8개의 비트를 가므로 64비트 정수는 메모리에서 8개의 연속된 바이트에 저장된답니다. => 메모리 조각에 8개의 자리를 차지하는 식으로 메모리에 쌓이게 된다.

1) java, c와 다른 javascript의 메모리 관리 방식(feat. 정수형)

8을 저장하는 방법

- JS : let a = 8(8byte)

- JAVA

byte a = 8(1byte)

short a = 8(2byte)

int a = 8(4byte)

long a = 8(16byte)

java 또는 c언어가 초기에 등장했을 때 숫자 데이터 타입은 크기에 따라 다양하게 지정해줘야 할 만큼 개발자가 handling 할 요소들이 많았어요. 하지만 javascript는 이런 부분에서는 상당히 편리하죠. 메모리 이슈까지는 고민하지 않아도 되니까요 😎

 

2)식별자, 변수의 구분

var testValue = 3   => testValue는 식별자, 3은 변수

변수 = 데이터

식별자 = 변수명

 

 

변수 선언과 데이터 할당(기본형)

변수 할당 예시

/** 선언과 할당을 풀어 쓴 방식 */
var str;
str = 'test!';

/** 선언과 할당을 붙여 쓴 방식 */
var str = 'test!';

❓값을 바로 변수에 저장하지 않고 메모리에 따로 저장하는 이유(=무조건 새로 만드는 이유)

1. 자유로운 데이터 변환

이미 입력한 문자열이 길어진다면?

=>숫자는 항상 8byte로 고정이지만, 문자는 고정이 아니에요(영문 : 1byte, 한글 : 2byte). 그래서, 이미 1003 주소에 할당된 데이터를 변환하려 할 때 훨씬 더 큰 데이터를 저장하려 한다면 → 1004 이후부터 저장되어있는 모든 데이터를 오른쪽으로 다 미뤄야 하겠죠..!

 => 비효율적 => 별도 메모리에 데이터를 확보해 놓고 주소를 가져오는 것이 더 효율적이다.

 

2. 메모리의 효율적 관리

똑같은 데이터를 여러번 저장해야 한다면?

1만개의 변수를 생성해서 모든 변수에 숫자 1을 할당하는 상황을 가정해 봅시다. 모든 변수를 별개로 인식한다고 한다면, 1만개의 변수 공간을 확보해야 해요.

바로 대입하는 case) 숫자형은 8 바이트 고정이죠?

1만개 * 8byte = 8만 byte

변수 영역에 별도 저장 case)

변수 영역 : 2바이트 1만개 = ****2만바이트</aside>

ℹ️ 이해를 돕고자, 변수 영역에 저장되는 데이터는 2바이트로 가정했어요!
데이터 영역 : 8바이트 1개 = 8바이트 (데이터는 같기 때문에 1개만 저장)
총 : 2만 8바이트    => 8만 byte보다 훨씬 효율적

 

 

기본형 데이터와 참조형 데이터

1. 메모리를 기준으로 다시한번 생각해보는 두 가지 주요 개념

1)변수 vs 상수

변수 : 변수 영역 메모리를 변경할 수 있음 

상수 : 변수 영역 메모리를 변경할 수 없음

 

2)불변하다 vs 불변하지 않다

- 불변하다 : 데이터 영역 메모리를 변경할 수 없음 => 즉, 기본형타입

let num = 8 에서 

num = 9 으로 수정했을 때,

변수영역 => a 에 @5002이라는 주소 할당

메모리 영역 => @5002주소에 8을 할당, 8은 놔두고 새로운 영역에 @5003주소로 9를 할당하여 위 변수영역에 갈아 끼움 => 이때 @5002는 더 이상 사용되지 않기 때문에 가비지(쓰레기) 컬렉터의 수거 대상이 된다. 이런식으로 메모리 관리 => 즉 변수는 불변하다.

- 불변하지 않다 : 데이터 영역 메모리를 변경할 수 있음 => 객체형타입

 

2. 불변값과 불변성(with 기본형 데이터)

 a라는 변수가 abc에서 abcdef가 되는 과정을 통해 불변성을 유추해봅시다!

 'abc'라는 값이 데이터영역의 @5002라는 주소에 들어갔다고 가정할게요.
var a = 'abc';

'def'라는 값이 @5002라는 주소에 추가되는 것이 아니죠!
 @5003에 별도로 'abcdef'라는 값이 생기고 a라는 변수는 @5002 -> @5003
 즉, "변수 a는 불변하다." 라고 할 수 있습니다.
 이 때, @5002는 더 이상 사용되지 않기 때문에 가비지컬렉터의 수거 대상이 됩니다.
a = a + 'def';

 

3. 가변값과 가변성(with 참조형 데이터)

1) 참조형 데이터의 변수 할당 과정

// 참조형 데이터는 별도 저장공간(obj1을 위한 별도 공간)이 필요합니다!
var obj1 = {
	a: 1,
	b: 'bbb,
};

⬇️ 강의를 참고해서 아래 표를 직접 작성해보세요!

obj를 위한 별도 메모리 공간을 따로 둔다.

변수영역에 obj1를 만들어서 7103참조 =>  obj1의 별도의 메모리에 7103이라는 공간에 a와 참조값 들어있음 => 데이터 영역에 5001이라는 메모리에 값이 들어있음

// 참조형 데이터는 별도 저장공간(obj1을 위한 별도 공간)이 필요합니다! 
var obj1 = { a: 1, b: 'bbb, };

 

2) 기본형 데이터의 변수 할당 과정과 차이점 : 객체의 변수(프로퍼티) 영역의 별도 존재 여부 => obj를 위한 별도의 메모리 공간이 필요하다.

3) 참조형 데이터가 불변하지 않다(가변하다)라고 하는 이유

var obj1 = {
	a: 1,
	b: 'bbb',
};

// 데이터를 변경해봅시다.
obj1.a = 2;

변경할 값인 숫자 2를 데이터 영역에서 검색합니다.

=> 없네요! 2를 새로 메모리 주소에 추가하고, 해당 주소(ex : @5003)를 obj1을 위한 별도 영역에 갈아껴줍니다.

 

c. 데이터 영역에 저장된 값은 여전히 계속 불변값이지만, obj1을 위한 별도 영역은 얼마든지 변경이 가능해요. 이것 때문에 참조형 데이터를 흔히, **‘불변하지 않다(=가변하다)’**라고 합니다. => obj1의 메모리 영역도 데이터 영역에 포함되기 때문

 

4)중첩객체의 할당

var obj = {
	x: 3,
	arr: [3, 4, 5],
}

// obj.arr[1]의 탐색과정은 어떻게 될까요? 작성하신 표에서 한번 찾아가보세요!

⬇️ 강의를 참고해서 아래 표를 직접 작성해보세요!

- arr을 위한 메모리 영역도 따로 만들어줘야 한다.

- 데이터 영역에 값이 있을 경우 해당 주소를 참조한다.

자바스크립트에서 중첩객체란, 객체 안에 또 다른 객체가 들어가는 것을 말해요. 이번 주차 초반에 살펴보았듯이 객체는 배열, 함수 등을 모두 포함하는 상위개념이기 때문에 배열을 포함하는 객체도 중첩객체라고 할 수 있답니다.

 

- 참조 카운트가 0인 메모리 주소의 처리

💡 참조카운트란 객체를 참조하는 변수나 다른 객체의 수를 나타내는 값입니다. 참조 카운트가 0인 객체는 더 이상 사용되지 않으므로, 가비지 컬렉터에 의해 메모리에서 제거됩니다.

💡 객체를 참조하는 변수나 다른 객체의 수를 나타내는 값입니다. 
참조 카운트가 0인 객체는 더 이상 사용되지 않으므로, 
가비지 컬렉터에 의해 메모리에서 제거됩니다.

- 가비지컬렉터(GC, Garbage Collector)</aside>

💡 더 이상 사용되지 않는 객체를 자동으로 메모리에서 제거하는 역할을 합니다. 
자바스크립트는 가비지 컬렉션을 수행함으로써 개발자가 명시적으로 
메모리 관리를 하지 않아도 되도록 지원합니다. 자바스크립트 엔진에서 내부적으로 수행되며, 
개발자는 가비지 컬렉션에 대한 직접적인 제어를 할 수 없습니다.

 

 

 

4. 변수 복사의 비교

// STEP01. 쭉 선언을 먼저 해볼께요.
var a = 10; //기본형
var obj1 = { c: 10, d: 'ddd' }; //참조형

// STEP02. 복사를 수행해볼께요.
var b = a; //기본형
var obj2 = obj1; //참조형

 

 

 

5. 복사 이후 값 변경(객체의 프로퍼티 변경)

// STEP01. 쭉 선언을 먼저 해볼께요.
var a = 10; //기본형
var obj1 = { c: 10, d: 'ddd' }; //참조형

// STEP02. 복사를 수행해볼께요.
var b = a; //기본형
var obj2 = obj1; //참조형

b = 15;
obj2.c = 20;

❗obj2.c = 20으로 변경해서 주소가 @5004로 변경됨 => obj1.c의 참조주소도 @5004로 변경되버림

 

기본형과 참조형의 변수 복사 시 주요한 절차의 차이점은 다음과 같아요!

- 기본형

숫자 15라는 값을 데이터 영역에서 검색 후 없다면 생성

검색한 결과주소 또는 생성한 주소를 변수 영역 b에 갈아끼움

a와 b는 서로 다른 데이터 영역의 주소를 바라보고 있기 때문에 영향 없음

- 참조형

숫자 20이라는 값을 데이터 영역에서 검색 후 없다면 생성

검색한 결과주소 또는 생성한 주소 obj2에게 지정되어 있는 별도 영역(7103~)에 갈아끼움

obj1도 똑같은 주소를 바라보고 있기 때문에 obj1까지 변경이 됨

바로 아래와 같은 현상이 생기는 것이죠!

// 기본형 변수 복사의 결과는 다른 값!
a !== b;

// 참조형 변수 복사의 결과는 같은 값!(원하지 않았던 결과😭)
obj1 === obj2;

자, 복사까지는 할만 하셨죠? 기본형과 참조형의 두드러지는 차이는 복사한 후의 값 변경에서 일어나요. 한번 수행하고 표를 작성해 보시면서 어떤 차이가 있는지 찾아보도록 합시다 🔥 (값 변경 부분에 대한 작성도 위의 표에 해주세요!)

 

6. 복사 이후 값 변경 => 아예 obj2의 객체 자체를 변경

만약, 객체의 프로퍼티(=속성)에 접근해서 값을 변경하는 것이 아니라 객체 자체를 변경하는 방식으로 값을 바꾼다면 어떨까요? 아래 예제를 한번 같이 따라가볼까요? 🚀

//기본형 데이터
var a = 10;
var b = a;

//참조형 데이터
var obj1 = { c: 10, d: 'ddd' };
var obj2 = obj1;

b = 15;
obj2 = { c: 20, d: 'aaa'};

⬇️ 강의를 참고해서 아래 표를 직접 작성해보세요!

obj2를 위한 메모리 영역이 새롭게 생김 @8104~

완전히 다른 메모리를 참조하게 됨

 

obj2 변수는 참조형 데이터이고, 참조형 데이터의 값을 변경한 것임에도 불고하고 이전 케이스와는 다르게 obj1과는 바라보는 데이터 메모리 영역의 값이 달라졌습니다!

참조형 데이터가 ‘가변값’이라고 할 때의 ‘가변’은 참조형 데이터 자체를 변경할 경우가 아니라, 그 내부의 프로퍼티를 변경할 때 성립한다고 할 수 있겠네요 👍

 

 

* 위 내용은 스파르타 코딩클럽 JavaScript 문법 종합반 강의 내용입니다.