가비지 컬렉션에 대해 검색하면 자바스크립트가 아닌 자바(Java)의 가비지 컬렉션에 대한 정보가 많이 보인다.
왜 검색하면 전부 자바(Garbage Collection in Java) 이야기일까?
가비지 컬렉션(GC)은 언어 자체의 기능이라기보다는, 런타임 환경에서 작동하는 기능이다.
그래서 "어떤 언어가 GC를 어떻게 구현했는가"가 더 중요하게 여겨진다.
그 중에서도 자바(Java)는 GC를 가장 적극적이고 체계적으로 적용한 대표적인 언어이기 때문에, 관련 설명 자료가 많고 잘 정리되어 있다.
특히 자바에서는 GC의 내부 동작 원리, 메모리 구조(Heap, Stack), 알고리즘(Mark & Sweep, Generational GC 등) 등이 구체적으로 문서화되어 있어,
컴퓨터공학에서 GC 개념을 공부할 때 자주 인용되는 대표 사례가 된다.
자바스크립트도 가비지 컬렉션 기능을 내장하고 있다.
우리가 사용하는 JS 코드가 브라우저나 Node.js 환경에서 실행될 때,
해당 환경의 자바스크립트 엔진(V8, SpiderMonkey 등)이 메모리를 자동으로 관리해준다.
자바처럼 우리가 직접 조작할 일은 거의 없고, 자바스크립트 엔진이 알아서 해주는 쪽에 가깝다.
자바스크립트는 "도달 가능성(reachability)"이라는 개념을 기준으로
필요한 값은 남겨두고, 더 이상 접근할 수 없는 값은 메모리에서 제거한다.
‘도달 가능한(reachable)’ 값은 쉽게 말해 어떻게든 접근하거나 사용할 수 있는 값을 의미한다.
도달 가능한 값은 메모리에서 삭제되지 않는다.
아래에 있는 값들은 그 태생부터 도달 가능하기 때문에, 명백한 이유 없이는 삭제되지 않는다.
이런 값들은 루트(Root)라고 부른다.
루트에서 참조되는 값들은 도달 가능하다고 간주되고,
그 값이 또 다른 객체를 참조하면 그것도 도달 가능한 값이 된다.
자바스크립트 엔진 내에선 가비지 컬렉터(garbage collector)가 끊임없이 동작합니다. 가비지 컬렉터는 모든 객체를 모니터링하고, 도달할 수 없는 객체는 삭제합니다.
let user = { name: "John" };
user = null;
→ 더 이상 John이라는 객체를 참조하는 변수가 없기 때문에
GC는 이 객체를 메모리에서 제거할 수 있다.
let user = { name: "John" };
let admin = user;
user = null;
→ user는 비워졌지만 admin이 여전히 John을 참조하고 있으므로,
메모리에서 제거되지 않는다.
admin = null까지 해야 GC 대상이 된다.
function marry(man, woman) {
woman.husband = man;
man.wife = woman;
return {
father: man,
mother: woman
};
}
let family = marry({ name: "John" }, { name: "Ann" });
delete family.father;
delete family.mother.husband;
family = null;

John, Ann은 여전히 서로를 참조하고 있지만자바스크립트 엔진은 mark-and-sweep이라는 알고리즘으로 GC를 수행한다.

이 과정을 페인트로 칠한다고 상상하면 쉽다.
루트에서 출발해서 참조를 따라가며 객체에 색을 칠하고,
색칠이 안 된 객체는 쓸모 없다고 판단해 버린다.
자바스크립트 엔진은 GC를 더 효율적으로 하기 위해 다양한 전략을 쓴다: