JavaScript (7) - 가비지 컬렉션(GC)란?
2025. 11. 30. 20:58ㆍfront-end/JavaScript
728x90
JavaScript 가비지 컬렉션(GC)
더 이상 사용되지 않는 메모리를 자동으로 해제해주는 엔진 내부 기능.
자바스크립트는 개발자가 malloc() 같은 걸 직접 쓰지 않기 때문에, 대신 엔진(V8 등)이 알아서 사용 여부를 판단하고 메모리를 해제함
GC는 “어떤 메모리를 버릴지” 어떻게 판단할까?
핵심 개념: Reachability(도달 가능성)
- 어딘가에서 접근 가능한 값이면 = 살아있음 (해제 X)
- 어디에서도 접근할 수 없게 되면 = 죽음 (해제 O)
도달 가능한 시작점(roots):
- 전역 객체 (window, global)

- 현재 실행 중인 함수 스코프
- 클로저에 묶인 변수
- call stack에 존재하는 변수들
예제 1
let a = { name: '홍소영' };
let b = a;
// 이제 a, b 둘 다 이 객체를 참조함.
a = null;
// 그래도 b가 객체를 가지고 있으므로 GC 대상 아님.
b = null;
// 이제 어떤 곳에서도 접근 불가 → GC가 해제
예제 2 - 함수 스코프
function test() {
const temp = { x: 1 };
return temp.x;
}
test(); // temp 객체는 사용 후 어디에서도 접근 불가 → GC 해제
예제 3 - 클로저 때문에 GC 안되는 경우
function outer() {
const big = new Array(100000).fill('*'); // 큰 메모리
return function inner() {
console.log(big[0]);
};
}
const fn = outer();
fn();
big은 inner()가 참조하기 때문에 outer()가 끝나도 메모리가 해제되지 않음.
→ 클로저는 GC에서 자주 발생하는 메모리 유지 원인
React / Next.js 에서 자주 발생하는 메모리 누수 원인
예제 1 - 이벤트 리스너 제거 안함
useEffect(() => { window.addEventListener('resize', handler); return () => window.removeEventListener('resize', handler); }, []);
예제 2 - setInterval / setTimeout 클리어 안함
useEffect(() => { const id = setInterval(...); return () => clearInterval(id); }, []);
예제 3 - WebSocket / SSE 연결 종료 안함
useEffect(() => { const ws = new WebSocket(...); return () => ws.close(); }, []);
GC는 “즉시” 동작하지 않음
- 일정한 타이밍에 검사하고 정리함
- 브라우저나 Node가 바쁠 때는 뒤로 밀릴 수 있음
- 전체 힙 크기가 커지면 GC 횟수가 증가 → 성능 저하 가능
GC 알고리즘 (간단 버전)
1) Mark-and-Sweep (표준)
- root부터 도달 가능한 객체에 마크(mark)
- 마크 안 된 객체는 모두 삭제(sweep)

2) Generational GC (V8)
'대부분의 객체는 금방 죽는다. 오래 살아남은 객체만 따로 관리하자!' V8엔진이 효율적으로 데이터를 관리하기 위한 핵심전략
- 새로 생성된 객체는 ‘young generation’
- 일정 시간 살아남으면 ‘old generation’ 이동
- young GC는 매우 빠름
- Young Generation (새 객체가 젤 처음 생성되는 구역)
- 대부분의 객체는 매우 짧은 시간만 존재한다.
- 그래서 Young 영역은 매우 자주 가비지 컬렉션을 한다.
- 이 청소를 Scavenge(스캐빈지) 라고 부른다.
- 빠르게 처리되도록 크기가 작고 정리 알고리즘도 간단하게 되어 있음.
- Young GC 시나리오
- 새로 만든 객체 = Young 영역에 저장
- 조금 있다가 GC 실행
- 아직 살아있는 객체만 → Old 영역으로 이동(=promotion)
- 죽은 객체는 Young에서 즉시 제거
- Old Generation (오래 살아남은 객체들이 저장되는 구역)
- Young GC에서 살아남아서 promotion된 객체들이 있는 곳
- 여기 있는 객체들은 생명주기가 긴 경우가 많음
- 크기가 크고, GC 빈도는 Young보다 훨씬 적음
- 대신 Mark-Sweep / Mark-Compact 같은 무거운 알고리즘 사용
왜 이렇게 나누는 걸까?
- JS의 대부분 객체는 금방 사라진다
함수 스코프 안에서 빠르게 만들고 금방 버려짐
→ Young Generation에서 빠르게 정리하는 게 효율적 - 오래 살아남는 객체는 비용 비싸도 천천히 검사해도 된다
예: 전역 상태, 싱글톤 객체 등 - 메모리 정리 속도가 훨씬 빨라짐
728x90
'front-end > JavaScript' 카테고리의 다른 글
| JavaScript (9) - 자바스크립트 런타임 구조(Runtime Architecture)/동작 원리 (0) | 2025.12.04 |
|---|---|
| JavaScript (8) - 비동기 프로그래밍 (0) | 2025.12.03 |
| 직접만든 라이브러리 npm package 배포하기 (모듈 배포, 버전업 후 배포실패시 캐시 삭제) (0) | 2024.02.03 |
| Javascript debugger (1) - 브라우저를 코딩 에디터로 사용하기 (0) | 2024.02.01 |
| JavaScript (6) - 호이스팅(Hoisting), 변수 선언의 실행 시점 (2) | 2023.12.04 |