[꼼꼼한 개발자] 꼼코더
[JS] - 가비지 컬렉션 (원피스로 이해하는 가비지 컬렉션)간단하고 쉽게 이해하기 본문
🧑🏻💻 소개
이 글에서는 자바스크립트 가비지 컬렉션을 원피스 캐릭터에 비유해 정말 쉽게 설명하려고 한다.
참조가 끊기면 메모리에서 사라지는 원리와 Mark & Sweep 알고리즘, 메모리 누수 주의까지 재미있게 풀어보겠다!
(마지막 눈물 주의 🥲)
🧠 가비지 컬렉션(Garbage Collection)이란?
우리가 생성한 모든 값(변수, 객체, 함수 등)은 메모리에 저장된다.
하지만 “더 이상 사용되지 않는 값”들은 불필요하게 메모리를 차지하곤 한다..
그래서 자바스크립트는 자동으로 메모리를 관리해 주는 기능(가비지 컬렉터)을 가지고 있으며
그 가비지 컬렉터가 이를 자동으로 찾아서 삭제(clean up) 해주는 과정(가비지 컬렉션)을 실행한다.
따라서 JS는 C언어처럼 명령어로 직접 메모리를 관리하지 않아도 된다.
(그렇다고 신경쓰지 않아도 된다는건 아니니 쭉 읽어보도록 하자!)
➡️ 가비지 컬렉션 (Garbage Collection)
불필요한 메모리를 자동으로 정리하는 메커니즘 또는 과정 = 청소 작업 자체
➡️ 가비지 컬렉터(Garbage Collector)
더 이상 사용되지 않는 메모리(데이터)를 찾아서 자동으로 정리하는 자바스크립트 엔진의 기능 = 청소부(도구)
🤔 사용되지 않는 메모리란? (가비지 컬렉션 원리 - 사라진 해적왕 비유)
간단히 말해, ‘더 이상 참조되지 않는 값’을 말한다.
아래 코드에서 변수에 객체를 할당한 후 null을 재할당하는 과정을 확인해 보자!
// 사람들은 해적왕을 로저라고 기억했습니다.(1번 사진)
// 🙋🏻♂️ : 해적왕은 누가 뭐래도 'Roger'야!!
let pirateKing = {
name: "Roger"
};
// 하지만 점점 해적왕이라는 말 자체가 사라지게 되고.. (2번 사진)
pirateKing = null;
// 자연스레 로저라는 인물도 잊혀져갔습니다..
// 따라서, 로저는 메모리에서 제거(가비지 컬렉션)됩니다. (2번 사진)


객체 { name: "Roger" }는 더 이상 접근할 방법이 없다. → 따라서 GC의 대상.
🤔 두 개의 참조 - 2개의 타이틀을 가진 사나이
또 다른 예시를 확인해 보자!
사람들은 해적왕을 '로저'라고 정했습니다.
'전설의 해적'은 자연스레 '해적왕'이 되었죠.
let pirateKing = {
name: "Roger"
};
let legendaryPirate = pirateKing;

시간이 지나 '해적왕'이라는 호칭 자체가 사라졌습니다.
pirateKing = null;
하지만 여전히 로저는 '전설의 해적'인건 변함이 없었죠 *(GC 대상 아님!)

하지만 점차 '전설의 해적' 호칭도 사라지게 되었고
legendaryPirate = null;
자연스레 '전설의 해적'이자 '해적왕'이었던 '로져'는 거론될 호칭이 없어 완전히 잊혀 갔습니다..
따라서, 로저는 메모리에서 제거(가비지 컬렉션)됩니다.

쉽게 말해 ‘접근할 수 없다면 GC의 대상이 되는구나!’라고 이해하면 쉽다!
이제 감이 잡혔다면 이어서 GC에 대해서 자세히 알아보자
🔍 GC가 동작하는 시점은?
자바스크립트는 명시적인 타이밍 없이 백그라운드에서 주기적으로 메모리를 검사하고 GC를 수행한다.
이 동작은 V8 엔진, SpiderMonkey, Chakra 등 엔진마다 방식이 다를 수 있지만, 원리는 비슷하다.
📦 자바스크립트 Mark & Sweep 알고리즘 (가비지 컬렉션 핵심)
자바스크립트는 우리 대신 필요 없는 메모리를 정리해 주는 똑똑한 청소 시스템을 갖고 있다 했는데
그 시스템이 작동하는 가장 대표적인 방식이 바로 “Mark & Sweep(표시하고 쓸어버리기)”이다
💡 작동 방식
- ‘루트(Root)’부터 출발해서 도달 가능한 객체를 ‘Mark(표시)’하고.
- 도달할 수 없는 객체는 ‘Sweep(제거)’한다.
루트(Root) 간단설명
- 전역 변수 (let, var, const로 선언된 변수들)
- 현재 실행 중인 함수의 지역 변수
- 클로저에서 참조되는 변수
쉽게 말해 ‘접근 가능한 값은 남기고, 쓸모없는 값은 쓸어버리는’ 메모리 청소 방식

📌 메모리 누수(Memory Leak) 주의!
자동 청소 기능 가비지 컬렉션이 있다고 해도, 메모리 누수는 실제로 자주 발생할 수 있다.
간단하게 2가지 정도만 알아보자!
👺 전역 변수에 계속 데이터 추가 - 저격왕의 가면
// 🏠 (써니호)창고에 소중히 보관 중인 저격왕 가면
let warehouse = {
item: "저격왕 가면"
};
- 아무도 쓰지 않지만, 여전히 (전역변수) 창고에 들어 있으므로 메모리에서 제거되지 않음!
💊 타이머(setInterval, setTimeout) 사용 후 해제 안 함 - 쵸파의 럼블볼
let rumbleBall = { type: "3단 변신 캡슐" };
// 쵸파가 5초 뒤에 변신할 준비
setTimeout(() => {
console.log(`${rumbleBall.type} 덕분에 쵸파가 변신 준비 완료!`);
}, 5000);
// 쵸파가 실수로 럼블볼을 잃어버림
rumbleBall = null;
- rumbleBall은 null로 재할당되었지만
- setTimeout의 콜백 함수가 클로저 형태로 이전 변수(rumbleBall)를 참조하고 있어서
- 자바스크립트 엔진은 아직 메모리에서 제거하지 않는다.
- 즉, 함수가 실행되어 참조가 완전히 끊기기 전까지는 해당 객체가 메모리에 남아 있게 된다.
- 따라서 꼭 clearTimeout이나 clearInterval을 써서 정리해 주도록 하자!
이제 마지막 감동의 스토리 예재를 끝으로 마무리해 보겠다!
☠️ 마크 앤 스위프 (Mark & Sweep)예제 - 메모리가 언제 죽는다고 생각하나?
원피스의 ‘드럼왕국(drumKingdom)’에는 의사가 3명이 있었다. [히루루크, 쿠레하, 쵸파]
function connectDoctors(hiruluk, kureha, chopper) {
hiruluk.friend = kureha; // '히루루크' 친구는 '쿠레하'
hiruluk.son = chopper; // '히루루크' 아들은 '쵸파'
kureha.friend = hiruluk; // '쿠레하' 친구는 '히루루크'
kureha.student = chopper; // '쿠레하' 의료제자는 '쵸파'
chopper.father = hiruluk; // '쵸파' 아버지는 '히루루크'
chopper.teacher = kureha; // '쵸파' 스승은 '쿠레하'
return {
firstDoctor: hiruluk,
secondDoctor: kureha,
thirdDoctor: chopper
};
}
// 드럼왕국의 의사 명단
let drumKingdom = connectDoctors(
{ name: "히루루크" },
{ name: "쿠레하" },
{ name: "쵸파" }
);
히루루크와 쿠레하는 서로를 친구라고 생각했었다.
쵸파는 쿠레하를 ‘의료스승’으로 히루루크는 ‘아버지’처럼 따랐다.
쿠레하는 쵸파를 ‘의료 제자’로 여겼고
히루루크는 쵸파를 ‘아들’처럼 여겼다…

하지만 쿠레하는 히루루크의 만행(강도, 방화, 평범한 감기를 중증으로 악화..등)을 보고 친구관계를 끊었다..
delete drumKingdom.secondDoctor.friend;
며칠 뒤 아픈 히루루크를 위해 쵸파는 약을 가지고 왔다. 🍄
쵸파가 약인 줄 알고 가져온 ☠️ 독버섯 수프를 먹고 위독해진 히루루크는
쵸파에게 사실을 숨긴 채 드럼왕국으로 달려가 죽음을 기다린다.
이때 드럼왕국 은 ‘히루루크’가 곧 죽을 것을 알고 첫 번째 의사 명단에서 제외시킨다.
delete drumKingdom.firstDoctor;

히루루크는 쿠레하에게 손절당하고, 왕국에서도 잊혔다.
하지만 GC에 의해 사라지지 않는다.
바로 여전히 그를 ‘아버지(father)’로 기억해 주는 단 하나의 존재 ‘쵸파’가 있기 때문이다..

사라지지 않는 히루루크가 말한다. (BGM ON)
“어이, 메모리는… 언제 죽는다고 생각하나···?”
“오류가 났을 때…? 아니.”
“delete 키워드를 만났을 때…? 아니야!!”
“···’ 루트객체’에게서 잊혀졌을 때다···!!!”

(정확히는 루트 객체에서 접근 불가할 때 입니다 😁)
😅 마무리
잘 이해가 되셨나요? 이해가 잘 되셨으면 좋겠네요!
자바스크립트 메모리 관리와 가비지 컬렉션의 원리를 알면, 불필요한 메모리 누수를 방지하고 성능을 최적화할 수 있습니다.
특히 대규모 프로젝트에서는 메모리 관리가 안정성과 직결되므로 꼭 알아두시면 좋습니다!
⁇ 번외 편 : 루트가 끊기게 된다면? - 버스터콜 발동
- 버스터콜 ⇒ 드럼왕국 지도에서 삭제 ⇒ 의사들 접근 불가 ⇒ GC 대상!
drumKingdom = null
