자바스크립트 가비지 콜렉션의 기준 (1)
크리스는 1장에서 자바스크립트 엔진에 **가비지 콜렉터(Garbage Collector, 이하 GC)**라는 자동 청소부가 살고 있다는 사실을 알았다.
하지만 여전히 의문이 남는다.
"청소부가 내 마음을 읽는 독심술사는 아니잖아. 내가 '앞으로 이 변수는 안 쓸 거야'라고 생각만 했는데, 그걸 어떻게 알고 지우지?"
만약 GC가 엉뚱한 데이터를 "쓰레기"라고 착각해서 지워버리면 프로그램은 에러를 뿜으며 죽을 것이다. 반대로 쓰레기를 안 치우면 메모리가 터진다.
그래서 GC에게는 아주 엄격한 **"쓰레기 판별 기준"**이 있다.
오늘은 과거에 쓰였던 방식과 그 치명적인 약점, 그리고 현재의 표준 기준인 **도달 가능성(Reachability)**에 대해 알아보자.
1. "필요 없음" vs "도달할 수 없음"
우리는 흔히 "필요 없는 메모리"를 해제한다고 말한다. 하지만 컴퓨터 입장에서 "필요 없다"는 말은 너무 주관적이다.
그래서 자바스크립트는 기준을 바꿨다.
"루트(Root)에서 시작해서 닿을 수 있는가?"
2. 과거의 기준: 참조 카운팅 (Reference Counting)
초창기 알고리즘이나 일부 오래된 브라우저(IE 6, 7 등)는 참조 카운팅이라는 단순한 방식을 썼다.
"나를 가리키는 화살표 개수가 0개면 쓰레기다."
아주 직관적이다. 누군가 나를 보고 있다면 나는 필요한 존재고, 아무도 나를 안 보면 나는 잊힌 존재라는 것이다.
JavaScript
// 객체 생성 (참조 카운트: 1) - 'user' 변수가 바라봄 let user = { name: "Chris" }; // 다른 변수도 바라봄 (참조 카운트: 2) let admin = user; // user 변수가 손을 뗌 (참조 카운트: 1) - 아직 admin이 잡고 있으니 안 지워짐 user = null; // admin 변수도 손을 뗌 (참조 카운트: 0) -> 🗑️ 수거 대상! admin = null;
이 방식은 구현이 쉽고, 카운트가 0이 되는 순간 즉시 메모리를 회수할 수 있다는 장점이 있었다. 하지만 치명적인 약점이 하나 있었다.
3. 치명적 약점: 순환 참조 (Circular Reference)
크리스가 결혼 정보를 담는 객체를 만들었다고 가정해보자.
JavaScript
function marry(man, woman) { woman.husband = man; man.wife = woman; return { father: man, mother: woman } } let family = marry({ name: "Chris" }, { name: "Jane" });
여기서 Chris와 Jane은 서로를 가리키고 있다. (husband, wife)
이때, 외부에서 이 가족에 대한 참조를 끊어버리면 어떻게 될까?
JavaScript
family = null; // 외부 연결 끊음
우리의 상식으로는 family가 없어졌으니 Chris와 Jane도 메모리에서 사라져야 한다.
하지만 참조 카운팅 방식에서는 사라지지 않는다!
서로가 서로의 손을 잡고 있는 무인도에 고립된 커플과 같다.
외부(Root)에서는 이들에게 갈 방법이 없는데, 자기들끼리 참조 카운트를 1로 유지하고 있어서 영원히 메모리에 남아있는다. 이것이 과거 인터넷 익스플로러(IE)에서 메모리 누수가 빈번했던 주원인이었다.
4. 해결책: 관점을 바꿔라
참조 카운팅의 한계 때문에, 모던 브라우저들은 **"개수 세기"**를 그만두었다.
대신 서두에 말했던 **"도달 가능성(Reachability)"**을 기준으로 알고리즘을 변경했다.
루트에서 시작해서 연결된 선을 따라가 본다.
순환 참조로 자기들끼리 묶여 있어도, 루트에서 연결된 선이 없다면 도달할 수 없는 섬으로 간주하고 가차 없이 쓸어버린다.
이 "도달 가능성"을 판단하기 위해 자바스크립트 엔진이 사용하는 구체적인 알고리즘이 바로 **표시하고 쓸기(Mark-and-Sweep)**다.
핵심 정리
그렇다면 GC는 구체적으로 언제, 어떻게 메모리를 훑으면서 "살아남을 자"와 "죽을 자"를 표시할까?
브라우저가 멈칫하는 순간을 최소화하기 위한 고도화된 기술, Mark-and-Sweep의 동작 원리를 다음 장에서 자세히 알아보자.
7장 자바스크립트에서 메모리 - 3. 표시하고 쓸기(Mark-and-Sweep) 알고리즘 편에서 계속된다.