메모리 관리 — 스택·힙·가상 메모리·GC
스택(식판 더미)·힙(창고)·가상메모리(OS가 만든 환상)·GC — 'Out of Memory'의 실체.
"메모리 누수"가 뭔지, 왜 재귀가 과하면 크래시하는지, 가비지 컬렉터가 뭘 하는지 이해하면 Claude가 만든 코드의 메모리 문제를 볼 수 있다.
프로세스 메모리는 크게 5영역. 아래부터 코드(기계어) · 전역/정적 · 힙(heap) · 스택(stack). 힙은 아래서 위로, 스택은 위에서 아래로 자라며 가운데에서 만난다.
| 영역 | 관리자 | 특징 | 할당 속도 |
|---|---|---|---|
| 스택 | 자동 (함수 진입/종료) | LIFO, 함수 지역변수 | 매우 빠름 |
| 힙 | 수동 or GC | 임의 크기·수명 | 빠름 |
| 정적(static) | 컴파일러 | 프로그램 수명 = 데이터 수명 | — |
| 코드(text) | OS | 읽기 전용 | — |
function outer() {
const a = 1; // 스택 (지역변수)
const arr = new Array(1000); // 참조는 스택, 실제 데이터는 힙
inner();
}
function inner() {
const b = 2; // 스택
// outer 리턴 시 a, arr 참조 소멸 → arr은 GC 대상
}
outer();
// 재귀가 과하면?
function recurse() { recurse(); } // 스택이 계속 쌓이다 오버플로
// → Maximum call stack size exceeded
// 메모리 누수
const cache = [];
function leak(x) {
cache.push(x); // 영원히 안 지워짐 → 힙 무제한 증가
}스택 오버플로는 재귀 깊이 과다(함수 스택 프레임이 쌓임), 힙 오버플로(OOM)는 무한히 객체 생성 후 놓지 않음. 원인이 전혀 다르다.
가상 메모리(Virtual Memory) — 각 프로세스는 "나 혼자 4GB/64비트 주소공간을 다 쓰고 있어"라고 착각한다. 실제로는 OS가 페이지 단위(보통 4KB)로 물리 RAM 일부만 매핑. 부족하면 스와핑으로 디스크(SSD)의 페이지 파일에 잠깐 내려둠(엄청 느려짐).
스와핑이 시작되면 100~1000배 느려진다. 활성 디스크 때문에 컴퓨터가 멈춘 것처럼 보이는 현상의 본질. 해결: RAM 추가, 또는 메모리 사용량 줄이기.
가비지 컬렉션(GC) — 힙의 객체 중 더 이상 참조되지 않는 것을 자동 회수. JS·Python·Java·Go가 GC 언어. C/C++/Rust는 수동(malloc/free) 또는 컴파일 시점 관리(Rust 소유권).
| GC 유형 | 어떻게 | 언제 불편 |
|---|---|---|
| Mark-Sweep | 도달 가능한 객체 표시 후 나머지 삭제 | 수집 중 멈춤(stop-the-world) |
| Generational | 젊은 객체는 자주, 오래된 건 가끔 | 대부분 현대 JS·Java 기본 |
| 참조 카운팅 | 참조 수가 0되면 즉시 해제 | 순환 참조 처리 어려움 (Python `gc` 보완) |
// 메모리 누수 패턴 3종 (Claude도 종종 만든다)
// 1) 전역 캐시에 무한 push
const cache = [];
app.get("/api", (req) => cache.push(req)); // 영원히 쌓임
// 2) 제거 안 하는 이벤트 리스너
window.addEventListener("resize", handler); // 페이지 떠날 때 removeEventListener 필요
// 3) 클로저에 큰 객체 가둠
function makeHandler() {
const bigData = new Array(1_000_000);
return () => bigData.length; // 핸들러가 살아있는 한 bigData도 살아있음
}
// 진단:
// Chrome DevTools → Memory 탭 → Heap snapshot → Retained Size 큰 객체 추적
// Node.js: node --inspect app.js + DevTools connect"앱이 느려지다 크래시"는 대부분 이 셋 중 하나. Claude에게 "이 코드 메모리 누수 가능 지점 찾아줘"라고 요청하자.
재귀 호출이 과도하게 깊어질 때 터지는 에러의 정식 이름은?
JS의 Array/Object 같은 힙 객체는 참조가 사라져도 수동으로 free해야 한다.
물리 RAM이 부족해 OS가 디스크에 메모리를 임시 내려놓는 동작의 이름은?