๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๋นˆ ๊ตฌ๋ฉ ์ฑ„์šฐ๊ธฐ

[Java][JVM] StackOverflowError์˜ ์›์ธ๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

์ถœ์ฒ˜

ChatGPT


StackOverflowError๋Š” ์ž๋ฐ” ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋กœ, ํ˜ธ์ถœ ์Šคํƒ์˜ ์ตœ๋Œ€ ํฌ๊ธฐ๋ฅผ ์ดˆ๊ณผํ•  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค. ์ด๋Š” ๋ณดํ†ต ๋ฌดํ•œ ์žฌ๊ท€ ํ˜ธ์ถœ์ด๋‚˜ ๋„ˆ๋ฌด ๊นŠ์€ ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ๋กœ ์ธํ•ด ์Šคํƒ ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๊ณ ๊ฐˆ๋  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค.

 

StackOverflowError์˜ ์›์ธ

1. ๋ฌดํ•œ ์žฌ๊ท€ ํ˜ธ์ถœ Infinite Recursion

์žฌ๊ท€ ํ•จ์ˆ˜๊ฐ€ ์ข…๋ฃŒ ์กฐ๊ฑด ์—†์ด ์ž์‹ ์„ ๊ณ„์† ํ˜ธ์ถœํ•  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์ž˜๋ชป๋œ ์žฌ๊ท€ ํ˜ธ์ถœ์ด ์ข…๋ฃŒ๋˜์ง€ ์•Š๊ณ  ๊ณ„์† ๋ฐ˜๋ณต๋˜๋Š” ๊ฒฝ์šฐ์ด๋‹ค.

public void recursiveMethod() {
    recursiveMethod(); // ์ข…๋ฃŒ ์กฐ๊ฑด ์—†์ด ๊ณ„์† ์ž์‹ ์„ ํ˜ธ์ถœ
}

 

2. ๋„ˆ๋ฌด ๊นŠ์€ ์žฌ๊ท€ ํ˜ธ์ถœ Too Deep Recursion

์žฌ๊ท€ ํ˜ธ์ถœ์ด ์ข…๋ฃŒ ์กฐ๊ฑด์ด ์žˆ์–ด๋„, ์žฌ๊ท€ ๊นŠ์ด๊ฐ€ ๋งค์šฐ ๊นŠ์–ด ์Šคํƒ์ด ์ดˆ๊ณผ๋  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์žฌ๊ท€ ๊นŠ์ด๊ฐ€ ๋„ˆ๋ฌด ๊นŠ์–ด ์Šคํƒ ํ”„๋ ˆ์ž„์„ ์ดˆ๊ณผํ•  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค.

public int factorial(int n) {
    if (n == 1) return 1;
    return n * factorial(n - 1);
}
// ํฐ ๊ฐ’์œผ๋กœ ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ, ๊นŠ์ด๊ฐ€ ๋งค์šฐ ๊นŠ์–ด์ ธ StackOverflowError ๋ฐœ์ƒ ๊ฐ€๋Šฅ

 

3. ๋ฌดํ•œ ๋ฃจํ”„์™€ ๊ฐ™์€ ์ž˜๋ชป๋œ ๋ฐ˜๋ณต ๊ตฌ์กฐ

๋ฃจํ”„ ๋‚ด์—์„œ ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ˜๋ณต ํ˜ธ์ถœํ•˜๋ฉด์„œ ์ข…๋ฃŒ ์กฐ๊ฑด์ด ์—†๊ฑฐ๋‚˜ ์กฐ๊ฑด์ด ์ ์ ˆํ•˜๊ฒŒ ์„ค์ •๋˜์ง€ ์•Š์œผ๋ฉด ์Šคํƒ์ด ์ดˆ๊ณผ๋  ์ˆ˜ ์žˆ๋‹ค.

 

StackOverflowError ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

1. ์žฌ๊ท€ ํ•จ์ˆ˜์˜ ์ข…๋ฃŒ ์กฐ๊ฑด ํ™•์ธ ๋ฐ ์ˆ˜์ •

์žฌ๊ท€ ํ•จ์ˆ˜๊ฐ€ ํ•ญ์ƒ ์ข…๋ฃŒ๋  ์ˆ˜ ์žˆ๋„๋ก ์ ์ ˆํ•œ ์ข…๋ฃŒ ์กฐ๊ฑด์„ ์„ค์ •ํ•ด์•ผ ํ•œ๋‹ค.

์ข…๋ฃŒ ์กฐ๊ฑด์ด ์ œ๋Œ€๋กœ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์ข…๋ฃŒ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋  ๋•Œ ์žฌ๊ท€ ํ˜ธ์ถœ์ด ์ข…๋ฃŒ๋˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

public void recursiveMethod(int count) {
    if (count == 0) return; // ์ข…๋ฃŒ ์กฐ๊ฑด์„ ๋ช…ํ™•ํžˆ ์„ค์ •
    recursiveMethod(count - 1);
}

 

2. ์žฌ๊ท€ ํ˜ธ์ถœ ๊นŠ์ด ์ค„์ด๊ธฐ

์žฌ๊ท€ ํ˜ธ์ถœ์˜ ๊นŠ์ด๋ฅผ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ตœ์ ํ™”ํ•œ๋‹ค.

์žฌ๊ท€ ํ˜ธ์ถœ์„ ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜, Tail Recursion Optimization(Tail Call Optimization)์ด ๊ฐ€๋Šฅํ•˜๋ฉด ํ™œ์šฉํ•œ๋‹ค.

public int factorial(int n) {
    int result = 1;
    for (int i = 2; i <= n; i++) {
        result *= i;
    }
    return result;
}

 

 

 

3. ๋ฉ”๋ชจ์ด์ œ์ด์…˜(Memoization) ์‚ฌ์šฉ

์žฌ๊ท€ ํ˜ธ์ถœ์˜ ์ค‘๋ณต ๊ณ„์‚ฐ์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•ด ์ด๋ฏธ ๊ณ„์‚ฐ๋œ ๊ฐ’์„ ์ €์žฅํ•˜๊ณ  ์žฌ์‚ฌ์šฉํ•œ๋‹ค.

์ด๋Š” ํŠนํžˆ ํ”ผ๋ณด๋‚˜์น˜ ์ˆ˜์—ด๊ณผ ๊ฐ™์€ ๊ณ„์‚ฐ์— ์œ ์šฉํ•˜๋‹ค.

private static Map<Integer, Integer> memo = new HashMap<>();

public int fibonacci(int n) {
    if (n <= 1) return n;
    if (memo.containsKey(n)) return memo.get(n);
    
    int result = fibonacci(n - 1) + fibonacci(n - 2);
    memo.put(n, result);
    
    return result;
}

 

4. ์Šคํƒ ํฌ๊ธฐ ๋Š˜๋ฆฌ๊ธฐ

StackOverflowError๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์žฌ๊ท€ ๊นŠ์ด๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๋Œ€์‹ , ์ž๋ฐ”์˜ JVM ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด ์Šคํƒ ํฌ๊ธฐ๋ฅผ ๋Š˜๋ฆด ์ˆ˜ ์žˆ๋‹ค.

๋ช…๋ น์ค„์—์„œ -Xss ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด ์Šคํƒ ํฌ๊ธฐ๋ฅผ ์ง€์ •ํ•œ๋‹ค.

java -Xss2m YourProgram

 

๊ทธ๋Ÿฌ๋‚˜, ์Šคํƒ ํฌ๊ธฐ๋ฅผ ๋Š˜๋ฆฌ๋Š” ๊ฒƒ์€ ์ž„์‹œ ๋ฐฉํŽธ์ผ ๋ฟ ๊ทผ๋ณธ์ ์ธ ํ•ด๊ฒฐ์ฑ…์ด ์•„๋‹ˆ๋‹ค. ํ”„๋กœ๊ทธ๋žจ ๋กœ์ง์„ ๊ฒ€ํ† ํ•ด ์žฌ๊ท€ ๊นŠ์ด๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์ด ๋” ์ข‹๋‹ค.

 

5. ๋ฌดํ•œ ๋ฃจํ”„์™€ ๊ฐ™์€ ์ž˜๋ชป๋œ ๋ฐ˜๋ณต ๊ตฌ์กฐ ์ˆ˜์ •

์ฝ”๋“œ ๋‚ด์—์„œ ์ž˜๋ชป๋œ ์กฐ๊ฑด์œผ๋กœ ์ธํ•ด ๋ฐ˜๋ณต์ ์œผ๋กœ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์†Œ๋“œ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์ด๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค.

 

์š”์•ฝ

StackOverflowError๋Š” ๋Œ€๋ถ€๋ถ„ ์žฌ๊ท€ ํ˜ธ์ถœ์ด ์ž˜๋ชป๋œ ๊ฒฝ์šฐ์— ๋ฐœ์ƒํ•œ๋‹ค. ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์žฌ๊ท€ ํ•จ์ˆ˜์˜ ์ข…๋ฃŒ ์กฐ๊ฑด์„ ๋ช…ํ™•ํžˆ ์„ค์ •ํ•˜๊ณ , ์žฌ๊ท€ ๊นŠ์ด๋ฅผ ์ค„์ด๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ, ๋ฉ”๋ชจ์ด์ œ์ด์…˜๊ณผ ๊ฐ™์€ ์ตœ์ ํ™” ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘๋ณต ๊ณ„์‚ฐ์„ ๋ฐฉ์ง€ํ•˜๊ณ , ํ•„์š”ํ•œ ๊ฒฝ์šฐ JVM์˜ ์Šคํƒ ํฌ๊ธฐ๋ฅผ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทผ๋ณธ์ ์ธ ํ•ด๊ฒฐ์ฑ…์€ ์ฝ”๋“œ๋ฅผ ์ตœ์ ํ™”ํ•˜์—ฌ ์Šคํƒ ์‚ฌ์šฉ๋Ÿ‰์„ ์ค„์ด๋Š” ๊ฒƒ์ด๋‹ค.