메모리

MyeonghoonNam·2021년 8월 2일
1
post-thumbnail

자바스크립트의 메모리 구조를 통한 메모리 관리법을 알아보자.

자바스크립트 엔진메모리 할당 - 사용 - 해제의 과정을 거쳐 메모리를 관리한다.

자바스크립트 엔진콜스택메모리 힙이라는 메모리 구조를 통하여 데이터 및 코드 실행을 관리한다.

콜스택

  • 원시타입의 데이터가 저장된다.

1. 원시타입 변수 생성

원시타입의 데이터 값은 콜스택에 저장되고, 데이터 값이 저장된 콜스택의 주소값은 변수 a, b에 각각 저장된다.


2. 원시타입 재할당 - ex1


변수 a에 20을 재할당하면, 본인의 메모리에 있는 값을 변경하는게 아니라, 기존에 20을 저장하고 있는 메모리의 주소값으로 재할당된다. (원시타입의 값은 불변하기 때문이다.)

a에 저장된 주소값은 20을 가리키고 있던 b에 저장된 주소값과 동일해진다.


3. 원시타입 재할당 - ex2


변수 b에 30을 재할당하면, 변수 b의 주소값이 가리키는 메모리에 저장된 20을 30으로 교체하는게 아니라, 새로운 메모리를 확보하여 30을 저장하고, 변수 b에 저장된 주소값을 해당 주소값으로 교체한다.


4. 가비지 컬렉터


더 이상 참조되지 않는 데이터가비지 컬렉터에 의해 적절한 시점에 메모리에서 해제된다.


메모리 힙

  • 객체타입(참조타입)의 데이터가 저장된다.

1. 참조타입 변수 생성


배열과 같은 참조타입 데이터메모리 힙에 저장된다.

메모리 힙의 주소값은 콜 스택에 저장되고, a와 b에는 해당 콜스택의 주소값이 각각 저장된다.
(a는 const로, b는 let으로 선언된 것을 기억하자)

const로 선언된 a와 같은 상수에 push, pop 등을 통한 메소드로 데이터값이 변경되어져도 콜스택의 값(= 메모리 힙의 주소)이 변경되지 않았기에 오류가 발생하지 않는다.(메모리 힙의 값만 수정되었기 때문이다.)


2. 참조타입 데이터의 값 변경


const로 선언된 a와 같은 상수에 push, pop 등을 통한 메소드로 데이터값이 변경되어져도 콜스택의 값(= 메모리 힙의 주소)이 변경되지 않았기에 오류가 발생하지 않는다.

변수에 값을 재할당한게 아니라, 변수에 저장된 데이터를 수정한 것임에 주의하자.

메모리힙에 저장된 배열의 값을 변경하더라도, 배열이 저장된 메모리힙의 주소는 그대로이다.

즉, 콜스택에 저장된 메모리힙의 주소는 변경되지 않는다.

따라서 변수 a와 b에 저장된 주소값도 변하지 않는다.

a와 b입장에선 사실상 변한게 없는 것이다.

따라서 재할당이 필요 없는 경우, 참조타입은 const로 선언을 지향하자.


3. let으로 선언된 참조타입의 재할당

let으로 선언된 b에 다른 배열을 할당하고 있다.
이 경우, 메모리 힙에 새로운 주소가 확보되고, 새로운 배열이 저장된다.

콜스택에 저장되는 메모리힙의 주소값도 새로운 주소로 변경이 필요하다.
이때 콜스택도 기존에 저장되어 있던 주소값을 바꾸는게 아니라, 새로운 메모리를 확보해서 새로운 메모리힙의 주소값을 저장한다.

따라서 변수 b에 저장되는 콜스택의 주소값도 변경된다.

참조타입은 동일한 구성의 객체를 생성하더라도, 매번 새 메모리를 확보하여 새 객체를 생성한다.


4. const로 선언된 참조타입의 재할당

const로 선언된 a에 다른 배열을 할당하면 에러가 난다.

메모리힙에 새로운 공간을 확보해 다른 배열을 저장하면, 스택에서도 새로운 메모리를 확보해 해당 메모리힙의 주소를 저장해야하는데, 는 결과적으로 const로 선언된 a에 저장된 콜스택의 주소값도 변경하게 만든다.

const로 선언된 변수는 본인에게 할당된 콜스택 주소값의 변경을 허용하지 않는다.
(이 것이 const의 정확한 의미가 아닐까 한다. 그래서 const로 선언된 변수는 반드시 초기값을 할당하면서 선언해야 한다)

따라서 이 코드는 실행이 불가능하다.


가비지컬렉터

필요한 메모리를 자동 할당하고, 더 이상 사용하지 않는 메모리를 자동으로 회수하여 준다.

mark-and-sweep 알고리즘

메모리 관리에 사용되어지는 가비지컬렉터의 기본 알고리즘

  • 가비지 컬렉터는 루트(root) 정보를 수집하고 이를 ‘mark(기억)’ 합니다.
  • 루트가 참조하고 있는 모든 객체를 방문하고 이것들을 ‘mark’ 합니다.
  • mark 된 모든 객체에 방문하고 그 객체들이 참조하는 객체도 mark 합니다. 한번 방문한 객체는 전부 mark 하기 때문에 같은 객체를 다시 방문하는 일은 없습니다.
  • 루트에서 도달 가능한 모든 객체를 방문할 때까지 위 과정을 반복합니다.
  • mark 되지 않은 모든 객체를 메모리에서 삭제합니다.


참고자료

profile
꾸준히 성장하는 개발자를 목표로 합니다.

0개의 댓글