Home > CS > 2024 > πŸ’Ύ [CS] μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)λž€ λ¬΄μ—‡μΌκΉŒμš”?

πŸ’Ύ [CS] μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)λž€ λ¬΄μ—‡μΌκΉŒμš”?
CS

πŸ’Ύ [CS] μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)λž€ λ¬΄μ—‡μΌκΉŒμš”?

  • μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)λŠ” ν”„λ‘œκ·Έλž¨μ΄ μ‚¬μš© κ°€λŠ₯ν•œ μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory) μ˜μ—­μ„ μ΄ˆκ³Όν•˜μ—¬ 더 이상 데이터λ₯Ό μŒ“μ„ 수 μ—†κ²Œ λ˜λŠ” ν˜„μƒμ„ λ§ν•©λ‹ˆλ‹€.
  • 이둜 인해 ν”„λ‘œκ·Έλž¨μ΄ λΉ„μ •μƒμ μœΌλ‘œ μ’…λ£Œλ˜κ±°λ‚˜ μ‹œμŠ€ν…œ μ—λŸ¬κ°€ λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.

1️⃣ μŠ€νƒ(Stack)μ΄λž€?

  • μŠ€νƒ(Stack)은 ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ μ‹œ ν•¨μˆ˜ 호좜, 둜컬 λ³€μˆ˜ 등을 μ €μž₯ν•˜λŠ” λ©”λͺ¨λ¦¬ μ˜μ—­μž…λ‹ˆλ‹€.
    • μŠ€νƒ(Stack)은 ν›„μž…μ„ μΆ•(LIFO: Last In, First Out) λ°©μ‹μœΌλ‘œ μž‘λ™ν•˜λ©°, ν•¨μˆ˜κ°€ 호좜될 λ•Œλ§ˆλ‹€ ν•΄λ‹Ή ν•¨μˆ˜μ˜ 정보(예: λ§€κ°œλ³€μˆ˜, 둜컬 λ³€μˆ˜, λ°˜ν™˜ μ£Όμ†Œ λ“±)κ°€ μŠ€νƒ(Stack)에 β€œμŒ“μ΄κ³ (push)”, ν•¨μˆ˜κ°€ μ‘Έμš”λ˜λ©΄ μŠ€νƒ(Stack)μ—μ„œ β€œμ œκ±°(pop)β€λ©λ‹ˆλ‹€.

2️⃣ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)의 원인.

1️⃣ λ¬΄ν•œ μž¬κ·€ 호좜(Recursive Call)

  • μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)κ°€ κ°€μž₯ ν”νžˆ λ°œμƒν•˜λŠ” κ²½μš°λŠ” μž¬κ·€ ν•¨μˆ˜κ°€ μ’…λ£Œλ˜μ§€ μ•Šκ³  λ¬΄ν•œνžˆ 호좜될 λ•Œμž…λ‹ˆλ‹€.
  • μž¬κ·€ ν•¨μˆ˜λŠ” 자기 μžμ‹ μ„ ν˜ΈμΆœν•˜λ©΄μ„œ 맀번 μƒˆλ‘œμš΄ μŠ€νƒ ν”„λ ˆμž„(Stack frame)을 μŒ“κ²Œ λ˜λŠ”λ°, μ’…λ£Œ 쑰건 없이 계속 호좜되면 μŠ€νƒμ— 계속 μŒ“μ΄κ²Œ λ˜μ–΄ μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory)λ₯Ό μ΄ˆκ³Όν•˜κ²Œ λ©λ‹ˆλ‹€.

πŸ‘‰ μ˜ˆμ‹œ

public class StackOverflowExample {
    public static void recursiveMethod() {
        // μž¬κ·€ 호좜 - μ’…λ£Œ 쑰건이 μ—†μ–΄ λ¬΄ν•œ 호좜됨
        recursiveMethod();
    }
    
    public static void main(String[] args) {
        recursiveMethod();
    }
}
  • μœ„ μ½”λ“œμ—μ„œλŠ” recursiveMethod()κ°€ 자기 μžμ‹ μ„ κ³„μ†ν•΄μ„œ ν˜ΈμΆœν•˜κΈ° λ•Œλ¬Έμ— μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)κ°€ λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.

2️⃣ μ§€λ‚˜μΉ˜κ²Œ κΉŠμ€ ν•¨μˆ˜ 호좜 체인.

  • μ—¬λŸ¬ ν•¨μˆ˜κ°€ μ„œλ‘œλ₯Ό ν˜ΈμΆœν•˜λŠ” μƒν™©μ—μ„œλ„ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)κ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • 예λ₯Ό λ“€μ–΄, A() ν•¨μˆ˜κ°€ B()λ₯Ό ν˜ΈμΆœν•˜κ³ , B()κ°€ C()λ₯Ό ν˜ΈμΆœν•˜κ³ , … 이 과정을 맀우 깊게 λ°˜λ³΅ν•˜λ©΄ μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory)κ°€ 초과될 수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ“ μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory)

ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ 쀑에 ν•¨μˆ˜ 호좜과 κ΄€λ ¨λœ μž„μ‹œ 데이터λ₯Ό μ €μž₯ν•˜λŠ” λ©”λͺ¨λ¦¬ μ˜μ—­μž…λ‹ˆλ‹€.
주둜 지역 λ³€μˆ˜, ν•¨μˆ˜ λ§€κ°œλ³€μˆ˜, 리턴 μ£Όμ†Œ λ“±μ˜ 데이터λ₯Ό μ €μž₯ν•˜λ©°, ν•¨μˆ˜κ°€ 호좜될 λ•Œλ§ˆλ‹€ μƒˆλ‘œμš΄ μŠ€νƒ ν”„λ ˆμž„(Stack Frame)이 μƒμ„±λ˜κ³ , ν•¨μˆ˜κ°€ μ’…λ£Œλ˜λ©΄ ν•΄λ‹Ή μŠ€ν… ν”„λ ˆμž„μ΄ μ œκ±°λ©λ‹ˆλ‹€.

μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory)λŠ” LIFO(Last In, First Out, ν›„μž…μ„ μΆœ) ꡬ쑰둜 μž‘λ™ν•©λ‹ˆλ‹€.
즉, λ§ˆμ§€λ§‰μ— μ €μž₯된 데이터가 λ¨Όμ € 제거되며, ν•¨μˆ˜ 호좜이 μ€‘μ²©λ μˆ˜λ‘ μŠ€νƒ(Stack)의 κΉŠμ΄κ°€ κΉŠμ–΄μ§‘λ‹ˆλ‹€

3️⃣ λ„ˆλ¬΄ 큰 둜컬 λ³€μˆ˜ ν• λ‹Ή.

  • ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ λ„ˆλ¬΄ 큰 크기의 λ°°μ—΄μ΄λ‚˜ 객체λ₯Ό 둜컬 λ³€μˆ˜λ‘œ μ„ μ–Έν•  λ•Œλ„ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)κ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μŠ€νƒ(Stack)은 보톡 크기가 μ œν•œλœ λ©”λͺ¨λ¦¬ μ˜μ—­μ΄κΈ° λ•Œλ¬Έμ—, λ„ˆλ¬΄ λ§Žμ€ λ©”λͺ¨λ¦¬λ₯Ό μ‚¬μš©ν•˜λŠ” 둜컬 λ³€μˆ˜λ₯Ό μ„ μ–Έν•˜λ©΄ μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory)λ₯Ό μ΄ˆκ³Όν•˜κ²Œ λ©λ‹ˆλ‹€.

3️⃣ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°μ˜ κ²°κ³Ό.

  • μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)κ°€ λ°œμƒν•˜λ©΄ ν”„λ‘œκ·Έλž¨μ΄ λΉ„μ •μƒμ μœΌλ‘œ μ’…λ£Œλ˜κ±°λ‚˜, JVM(Java Virtual Machine)μ—μ„œ StackOverflowError와 같은 μ—λŸ¬κ°€ λ°œμƒν•©λ‹ˆλ‹€.
  • μž¬κ·€ ν•¨μˆ˜ ν˜ΈμΆœμ΄λ‚˜ κ³Όλ„ν•œ ν•¨μˆ˜ 호좜 체인을 μ‚¬μš©ν•  λ•Œ, 이런 λ¬Έμ œκ°€ λ°œμ…νž 수 μžˆμŒμ„ μΈμ§€ν•˜κ³  μ˜ˆλ°©ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.

4️⃣ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(StackOverflow)λ₯Ό λ°©μ§€ν•˜λŠ” 방법.

1️⃣ μž¬κ·€ ν•¨μˆ˜μ˜ μ’…λ£Œ 쑰건 확인.

  • μž¬κ·€ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  λ•ŒλŠ” λ°˜λ“œμ‹œ μ’…λ£Œ 쑰건(Base case, 베이슀 μΌ€μ΄μŠ€)을 λͺ…ν™•νžˆ μ •μ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.
    • μ’…λ£Œ 쑰건(Base case, 베이슀 μΌ€μ΄μŠ€)이 μ—†λ‹€λ©΄ λ¬΄ν•œνžˆ 호좜되기 λ•Œλ¬Έμ— μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(StackOverflow)λ₯Ό μœ λ°œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

πŸ‘‰ μ˜ˆμ‹œ

public class FactorialExample {
    public static int factorial(int n) {
        if (n <= 1) {
            return 1; // μ’…λ£Œ 쑰건: n이 1 μ΄ν•˜μΌ λ•Œ μž¬κ·€ 호좜 μ’…λ£Œ
        }
        return n * factorial(n - 1);
    }
    
    public static void main(String[] args) {
        System.out.println(factorial(5)); // μ •μƒμ μœΌλ‘œ 120 좜λ ₯
    }
}

2️⃣ μž¬κ·€ λŒ€μ‹  반볡문 μ‚¬μš©.

  • κ°€λŠ₯ν•œ 경우 μž¬κ·€ ν•¨μˆ˜ λŒ€μ‹  반볡문(loop)을 μ‚¬μš©ν•˜μ—¬ μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory) μ‚¬μš©μ„ 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€.
  • 반볡문(loop)은 μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory) λŒ€μ‹  νž™ λ©”λͺ¨λ¦¬(Heap Memory)λ‚˜ CPU λ ˆμ§€μŠ€ν„°(CPU Register)λ₯Ό μ‚¬μš©ν•˜λ―€λ‘œ, κΉŠμ€ μž¬κ·€ ν˜ΈμΆœμ„ 반볡문으둜 λ³€κ²½ν•˜λ©΄ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(StackOverflow)λ₯Ό 방지할 수 μžˆμŠ΅λ‹ˆλ‹€.

3️⃣ 꼬리 μž¬κ·€ μ΅œμ ν™”(Tail Recursion Optimization)

  • 일뢀 μ–Έμ–΄λŠ” 꼬리 μž¬κ·€(tail recursion)λ₯Ό μ΅œμ ν™”ν•˜μ—¬ μž¬κ·€ ν˜ΈμΆœμ„ 반볡문처럼 μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • ν•˜μ§€λ§Œ JavaλŠ” 기본적으둜 꼬리 μž¬κ·€(tail recursion) μ΅œμ ν™”λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμ—, μ£Όμ˜κ°€ ν•„μš”ν•©λ‹ˆλ‹€.
  • 꼬리 μž¬κ·€(Tail Recursion)λŠ” μž¬κ·€ 호좜이 ν•¨μˆ˜μ˜ λ§ˆμ§€λ§‰ μž‘μ—…μœΌλ‘œ 싀행될 λ•Œ, μ»΄νŒŒμΌλŸ¬κ°€ μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory)λ₯Ό μž¬μ‚¬μš©ν•˜μ—¬ μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)λ₯Ό λ°©μ§€ν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€.

πŸ“ 꼬리 μž¬κ·€(Tail Recursion)

μž¬κ·€ ν•¨μˆ˜μ˜ ν•œ ν˜•νƒœλ‘œ, ν•¨μˆ˜μ˜ λ§ˆμ§€λ§‰(꼬리) λ™μž‘μ΄ 자기 μžμ‹ μ„ ν˜ΈμΆœν•˜λŠ” 것을 λ§ν•©λ‹ˆλ‹€.
즉, μž¬κ·€ 호좜 뒀에 좔가적인 연산을 μˆ˜ν–‰ν•˜μ§€ μ•ŠλŠ” μž¬κ·€ λ°©μ‹μž…λ‹ˆλ‹€.
꼬리 μž¬κ·€(Tail Recursion)λŠ” μž¬κ·€ 호좜이 끝날 λ•Œ 더 이상 μ²˜λ¦¬ν•  μž‘μ—…μ΄ 남아 μžˆμ§€ μ•Šμ€ κ²½μš°μ— ν•΄λ‹Ήν•©λ‹ˆλ‹€.

4️⃣ μ μ ˆν•œ μŠ€νƒ 크기 μ„€μ •.

  • Javaμ—μ„œλŠ” JVM(Java Virtual Machine)의 μŠ€νƒ 크기λ₯Ό μ„€μ •ν•˜μ—¬ μŠ€νƒ μ˜€λ²„ ν”Œλ‘œμš°(Stack Overflow)λ₯Ό μ˜ˆλ°©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
    • -Xss μ˜΅μ…˜μ„ μ‚¬μš©ν•˜μ—¬ μŠ€νƒ 크기λ₯Ό μ‘°μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • κ·ΈλŸ¬λ‚˜, μŠ€νƒ 크기λ₯Ό λ¬΄μž‘μ • λŠ˜λ¦¬λŠ” 것은 근본적인 해결책이 μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— μž¬κ·€ ν˜ΈμΆœμ΄λ‚˜ ν•¨μˆ˜ 섀계λ₯Ό κ°œμ„ ν•˜λŠ” 것이 더 μ’‹μŠ΅λ‹ˆλ‹€.

πŸ‘‰ μ˜ˆμ‹œ

java -Xss2m MyProgram
  • μœ„ λͺ…령은 Java ν”„λ‘œκ·Έλž¨μ˜ μŠ€νƒ 크기λ₯Ό 2MB둜 μ„€μ •ν•©λ‹ˆλ‹€.

5️⃣ μš”μ•½

  • μŠ€νƒ μ˜€λ²„ ν”Œλ‘œμš°(Stack Overflow)λŠ” ν•¨μˆ˜ 호좜이 μŠ€νƒ λ©”λͺ¨λ¦¬(Stack Memory)의 ν•œκ³„λ₯Ό μ΄ˆκ³Όν–ˆμ„ λ•Œ λ°œμƒν•˜λ©°, 주둜 μž¬κ·€ ν•¨μˆ˜μ˜ λ¬΄ν•œ ν˜ΈμΆœμ΄λ‚˜ κΉŠμ€ ν•¨μˆ˜ 호좜 μ²΄μΈμ—μ„œ λ°œμƒν•©λ‹ˆλ‹€.
  • 이λ₯Ό λ°©μ§€ν•˜κΈ° μœ„ν•΄ μž¬κ·€ ν•¨μˆ˜μ˜ μ’…λ£Œ 쑰건을 λͺ…ν™•νžˆ μ„€μ •ν•˜κ³ , ν•„μš”ν•œ 경우 λ°˜λ³΅λ¬Έμ„ μ‚¬μš©ν•˜κ±°λ‚˜ JVM(Java Virtual Machine)의 μŠ€νƒ 크기λ₯Ό μ‘°μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • μŠ€νƒ μ˜€λ²„ν”Œλ‘œμš°(Stack Overflow)λ₯Ό ν”Όν•˜κΈ° μœ„ν•΄μ„œλŠ” ν”„λ‘œκ·Έλž¨μ˜ λ©”λͺ¨λ¦¬ μ‚¬μš©κ³Ό ν•¨μˆ˜ 호좜 ꡬ쑰에 λŒ€ν•œ μ² μ €ν•œ 이해와 관리가 ν•„μš”ν•©λ‹ˆλ‹€.