재귀함수란 특정 조건이 만족할 때까지 자기 자신을 호출하는 함수를 말한다. 재귀함수는 특정 조건을 만족할 때까지 계속 호출하기 때문에 반드시 탈출 조건이 필요한데, 만약 재귀 함수가 자기자신을 계속 호출하고 또 호출하고, 또 호출한다면, 어떤일이 일어날까?
이 글은 JavaScript 알고리즘 & 자료구조 마스터클래스를 참고하여 작성되었습니다.
자바스크립트 엔진은 메모리 힙(Memory Heap)과 호출 스택(Call Stack), 이렇게 두 가지 구성 요소로 이루어져 있다.
메모리 힙(Memory Heap)
변수와 객체에 대한 모든 메모리 할당이 발생한다.
호출 스택(Call Stack)
코드가 실행될 때, 즉 호출된 함수가 이곳에 쌓인다. Stack은 선입후출(FILO, Firsr In Last Out) 구조로, 맨 마지막으로 들어온 데이터가 가장 먼저 나가게 된다.
즉 함수를 호출하면 호출한 순서대로 Call Stack에 쌓이게 되는데, 맨 위에 쌓인 함수부터 제거되어 가장 마지막에 있는 함수는 모든 함수가 반환(Return)될 때까지 기다렸다가 가장 마지막에 제거된다.
예시코드를 크롬 콘솔창에 디버깅하여 Call Stack이 어떻게 쌓이고 제거되는지 직접 살펴보자!
여기 아침 직장인의 모습을 담은 예시 코드가 있다.
맨 처음 wakeUp
함수를 호출하면 takeShower
함수가 호출되고 리턴되어 제거된다. 그 후 eatBreakfast
함수를 호출하는데, 해당 함수 내부에서 cookFood
함수를 호출하고 있다. 그 후 마지막으로 console.log
가 출력되며 wakeUp
함수가 제거된다.
그럼 Call Stack엔 어떻게 쌓이고 제거되는지 확인해보자.
function takeShower() {
return "Showering!"
}
function eatBreakfast() {
let meal = cookFood();
return `Eating ${meal}`
}
function cookFood() {
let items = ["Oatmeal", "Eggs", "Protein Shake"]
return items[Math.floor(Math.random()*items.length)];
}
function wakeUp() {
takeShower();
eatBreakfast();
console.log("Ok ready to go to work!")
}
wakeUp();
Line20에 중단점을 추가하고 wakeUp
함수를 호출하면 Call stack에 wakeUp
함수가 추가된다.
그 후 아직 wakeUp
함수가 완료(return)되지 않았기 때문에 Call Stack에 제거되지 않고 다음 함수인 takeShower
가 호출되어 Call stack에 추가된다.
takeShower
함수가 값을 return하면,
함수가 종료되었기 때문에 Call stack에서 takeShower
함수가 제거된다.
wakeUp
함수는 그대로 Call stack에 있는 채로 다음 함수인 eatBreakfast
함수가 호출된다.
eatBreakfast
함수 내부에서 cookFood
함수를 호출하고 있으므로 Call stack에 cookFood
함수가 추가된다.
이때 wakeUp
와 eatBreakfast
는 아직 완료(return)되지 않았기 때문에 Call stack에 남아 있다.
cookFood
는 값을 리턴하고 Call stack에서 제거된다.
cookFood
에서 전달받은 값을 리턴한 후, 완료되어 eatBreakfast
함수는 Call stack에서 제거된다.
마지막으로 Call stack 남아있던 함수인 wakeUp
의 마지막 코드인 console.log
가 실행되면 Call stack에 모든 함수가 제거된다.
모든 것엔 한계가 존재한다. 단편적인 예로 number타입이 표현할 수 있는 최대값은 1.7976931348623157e+308이며 그 이상의 수는 Infinity로 표현된다. Call Stack도 마찬가지로, 스택의 사이즈는 한계가 존재하여 재귀함수 등을 통해 함수를 지속적으로 호출하여 스택이 계속 쌓이게 되면...
콜스택은 나 이제 한계야 ^^ 하고 오류를 뱉게 된다.
이것이 바로 유명한 STACK OVERFLOW이다.
스택 오버플로우(Stack Overflow)란 '스택이 넘쳐 흐른다'라는 의미 그대로,
스택 영역을 벗어나 다른 메모리 영역을 사용하지 못하도록 하는 것을 의미한다. 주로 재귀함수가 무한히 호출될 때 발생하며, 프로그램이 오작동하거나 종료될 수 있고, 보안상 취약점이 노출될 수 있어 발생하지 않도록 조심하는 것이 좋다.