Javascript

자바스크립트의 메모리 관리

프로그래밍 언어에서 메모리 생존 주기는

  1. 필요할 때 할당한다.
  2. 사용한다. (읽기, 쓰기)
  3. 필요 없어지면 해제한다.

 

C언어와 같은 저수준의 언어에서는 할당 및 해제의 과정이 명시적이다. 그러나 자바스크립트와 같은 고수준 언어에서의 메모리는 가비지 컬렉터에 의해 자동적으로 관리된다. 가비지 컬렉터는 말 그대로 가비지를 수집하는 녀석이다. 여기서 가비지란 불필요하게 메모리에 남아있는 데이터를 말한다. 변수나 함수 등은 메모리에 할당된다. 프로그램은 메모리에 할당된 데이터를 읽거나 쓰는 작업을 통해 자신의 역할을 수행한다. 메모리에 남아있는 데이터가 그 쓰임을 다하고 나면 어떻게 될까? 데이터가 더 이상 필요 없다면 메모리 할당은 해제되어야 한다. 자바스크립트에서 가비지 컬렉터는 ‘Mark and Sweep’이라는 알고리즘을 수행하며 불필요하게 남아있는 메모리를 회수한다.

 

해당 알고리즘을 설명하기에 앞서 MDN 등에서는 ‘Reference-Counting’ 알고리즘을 먼저 소개한다. 이 알고리즘은 더 이상 필요 없는 오브젝트를 어떤 다른 오브젝트도 참조하지 않는 오브젝트로 정의한다. 참조되지 않는 메모리는 회수된다. 어딘가로부터 참조되고 있다면? 가비지 컬렉터의 수거 대상이 될 수 없다. (나도 막연하게 가비지 컬렉터가 이 방식대로 동작한다고 생각해왔다.) 이 방식에는 명백한 한계가 존재한다. 만약 서로 참조(순환 참조)하고 있는 데이터가 있다면 불필요함에도 가비지 컬렉터의 수거 대상이 되지 않아 곧 메모리 누수의 결과로 이어진다.

 

위 방식의 한계를 극복할 수 있는 알고리즘이 ‘Mark and Sweep’ 알고리즘이다. 이 알고리즘은 roots로부터 참조되고 있는 데이터를 닿을 수 있는 오브젝트라고 간주한다. roots에서 참조하는 데이터, 그 데이터가 참조하고 있는 데이터, 또 그 데이터가 참조하는 데이터를 찾는 식의 방법으로 닿을 수 있는 오브젝트를 정의한다. 반대로 roots로부터 참조되고 있지 않다면 가비지 컬렉터의 수거 대상이 된다. (자바스크립트 환경에서 roots는 전역 객체를 의미한다.) 즉 이 알고리즘은 더 이상 필요 없는 오브젝트를 roots로부터 닿을 수 없는 오브젝트로 정의한다. 이 방식대로 라면 순환 참조는 더 이상 문제가 되지 않는다. 서로를 참조하고 있더라도 roots로부터 참조되지 않기 때문에 가비지로 분류되기 때문이다.

 

MDN에 의하면 2012년을 기준으로 모든 최신 브라우저는 ‘Mark and Sweep’ 알고리즘을 사용한다고 한다. 이전 방식의 한계를 개선했음에도 불구하고 수동 메모리 해제 기능, 즉 명시적으로 가비지 컬렉터를 작동시킬 수 없다는 점이 자바스크립트의 여전한 한계로 지적되고 있다. (다른 언어를 공부해 본 적이 없어서 이 내용에 대해선 잘 이해하지 못했다. 이것이 가능한 언어도 있나 본데..?) 명시적으로 가비지 컬렉터를 작동시킬 수는 없어도 직접 참조를 끊어줌으로써 메모리 누수를 어느 정도 방지할 수 있을 것 같긴 하다. 코어 자바스크립트에서는 클로저가 그 쓰임이 다한 경우 null 값을 할당하여 명시적으로 참조를 끊어주는 방식을 소개하기도 한다.

 

Reference: MDN

'Javascript' 카테고리의 다른 글

이벤트 복습하기  (0) 2022.01.09
map()과 forEach()차이  (0) 2022.01.07
Node.js - Express로 서버 만들기  (0) 2021.12.14
Node.js - http모듈로 서버 만들기  (0) 2021.12.14
Node.js - 모듈/동기/비동기  (0) 2021.12.14