Stack과 heap은 memory를 관리하는 방식의 차이로 이해할 수 있습니다. Stack은 함수가 호출될 때 stack frame이 쌓이고 함수가 끝나면 빠지는 구조라 수명이 예측 가능하고 빠릅니다. 지역 변수나 return address 같은 실행 흐름 정보가 여기에 관련됩니다.
Heap은 객체처럼 동적으로 생성되고 함수 호출이 끝나도 살아 있을 수 있는 데이터를 저장하는 영역입니다. JavaScript에서는 객체와 배열 같은 값이 heap에 만들어지고, 더 이상 도달할 수 없을 때 garbage collection 대상이 됩니다.
꼬리질문
조금 더 깊게 물어본다면
답변 뒤에 이어질 수 있는 질문들을 하나씩 열어볼 수 있어요.
stack overflow는 왜 발생하나요?
함수 호출이 너무 깊게 쌓여 stack 공간을 초과할 때 발생합니다. 재귀 종료 조건이 없거나 입력이 너무 커서 재귀 깊이가 과도한 경우가 대표적입니다.
call stack에 execution context가 계속 쌓인다고 연결해서 설명할 수 있습니다.
heap memory leak은 어떻게 생기나요?
더 이상 필요 없는 객체가 계속 참조되어 garbage collection 대상이 되지 못하면 생깁니다. 전역 cache, 정리되지 않은 listener, closure가 큰 객체를 잡고 있는 경우가 예입니다.
핵심은 객체가 “필요한지”가 아니라 “도달 가능한지”입니다.
primitive 값은 항상 stack에 저장되나요?
개념적으로는 primitive는 값 자체, 객체는 참조를 통해 heap에 있다고 설명할 수 있습니다. 하지만 실제 엔진 최적화까지 들어가면 더 복잡합니다.
너무 구현 세부를 단정하기보다 개념적 모델로 말하는 것이 안전합니다.
stack과 heap 중 어느 쪽이 더 빠른가요?
일반적으로 stack allocation은 단순하고 빠릅니다. heap allocation은 더 유연하지만 관리 비용이 큽니다.
다만 실제 성능은 runtime 최적화와 allocation 패턴에 따라 달라질 수 있습니다.
부가 설명
function createUser() { const name = "Joon"; const user = { name }; return user;}const savedUser = createUser();
createUser의 함수 호출 자체는 끝나지만 반환된 객체는 savedUser가 참조하고 있으므로 계속 살아 있을 수 있습니다. 이런 동적 객체는 heap 관점으로 설명할 수 있습니다.
언어와 runtime마다 세부 구현은 다르지만, stack은 함수 호출과 수명 관리가 단순한 영역이고 heap은 동적 할당과 더 긴 수명을 가진 영역입니다.
JavaScript 개발자에게는 이 구분이 closure, garbage collection, memory leak과 연결됩니다. 함수 실행이 끝나도 closure가 참조하는 객체는 heap에 남아 있을 수 있습니다.
한 줄 정리
stack은 함수 호출처럼 수명이 명확한 데이터를, heap은 동적으로 만들어져 더 오래 살아 있을 수 있는 객체를 관리하는 영역입니다.