반응형
1. ❓ StackOverflowError란 무엇인가요?
자바에서 각 스레드는 자신만의 스택(Stack) 영역을 가집니다. 메서드가 호출될 때마다 해당 메서드의 정보(로컬 변수, 매개변수, 복귀 주소 등)가 '스택 프레임'이라는 이름으로 쌓이게 됩니다.
StackOverflowError는 이 스택 영역의 제한된 용량을 초과하여 더 이상 프레임을 쌓을 수 없을 때 JVM이 던지는 에러입니다.
2. 🔍 주요 발생 원인
이 에러가 발생하는 원인은 대부분 코드의 논리적 오류에 있습니다.
- 무한 재귀(Infinite Recursion): 탈출 조건이 없는 재귀 함수가 자기 자신을 끝없이 호출할 때 발생합니다. (가장 흔한 원인)
- 상호 참조(Circular Reference): A 클래스의 toString()이 B를 호출하고, B의 toString()이 다시 A를 호출하는 구조일 때 발생합니다.
- 너무 깊은 메서드 호출: 재귀가 아니더라도 메서드 호출의 깊이(Depth)가 스택 크기보다 깊을 때 발생합니다.
- 대규모 로컬 변수: 메서드 하나에서 너무 많은 로컬 변수를 선언하여 스택 프레임 하나가 너무 클 때 드물게 발생합니다.
3. 🛠️ 실전! 해결 및 예방 전략
✅ 1. 재귀 탈출 조건(Base Case) 확인
재귀 함수를 작성할 때는 반드시 "언제 멈출 것인가"를 명확히 해야 합니다.
Java
// 잘못된 예: 무한 재귀
public int factorial(int n) {
return n * factorial(n - 1); // n이 0 이하일 때의 조건이 없음!
}
// 올바른 예
public int factorial(int n) {
if (n <= 1) return 1; // 탈출 조건 명시
return n * factorial(n - 1);
}
✅ 2. 반복문(Loop)으로 전환
메서드 호출 깊이가 너무 깊다면 재귀 대신 for나 while 문을 사용하는 것이 안전합니다. 반복문은 스택 프레임을 새로 생성하지 않기 때문에 메모리 효율적입니다.
✅ 3. 스택 크기 조절 (임시 방편)
정말로 깊은 호출이 필요한 로직이라면 JVM 옵션을 통해 스레드당 스택 크기를 키울 수 있습니다. (하지만 근본적인 해결책은 아닙니다.)
Bash
# 스택 크기를 2MB로 설정 (기본값은 보통 1MB 내외)
java -Xss2m -jar my-app.jar
💡 시니어의 조언: '꼬리 재귀 최적화'를 아시나요?
자바는 아쉽게도 언어 차원에서 **꼬리 재귀 최적화(Tail Call Optimization)**를 완벽히 지원하지 않습니다. 따라서 재귀 깊이가 수천 번 이상 깊어질 가능성이 있다면, 처음부터 스택 구조를 사용하는 반복문이나 함수형 프로그래밍의 스트림 처리를 고민하는 것이 '중급' 개발자의 센스입니다.
반응형
'개발 > Trouble Shooting' 카테고리의 다른 글
| 자바의 영원한 숙제: NullPointerException (NPE) 완벽 가이드 (0) | 2025.12.29 |
|---|---|
| 클래스가 어디로 사라졌을까? ClassNotFoundException 완벽 가이드 (0) | 2025.12.29 |
| 데이터베이스와의 소통 불능: SQLException 완벽 가이드 (0) | 2025.12.29 |
| 데이터 통신의 첫 번째 관문: IOException 완벽 이해하기 (0) | 2025.12.29 |
| 서버가 멈췄다! 자바 OutOfMemoryError(OOME) 완벽 분석 및 해결 가이드 (0) | 2025.12.29 |