[java] StackOverflowError에서 복구 할 수있는 이유는 무엇입니까?

StackOverflowErrorJava에서 a 가 발생한 후에도 실행을 계속할 수 있다는 사실에 놀랐습니다 .

나는 그것이 StackOverflowErrorError 클래스의 하위 라는 것을 알고 있습니다. Error 클래스는 “합리적인 응용 프로그램이 포착하려고 시도해서는 안되는 심각한 문제를 나타내는 Throwable의 하위 클래스”로 설명됩니다.

이것은 StackOverflowError와 같은 오류를 잡는 것이 실제로 허용되며 그렇게하지 않는 것은 프로그래머의 합리성에 달려 있다고 가정하는 규칙 이라기보다 권장 사항처럼 들립니다. 그리고이 코드를 테스트했는데 정상적으로 종료됩니다.

public class Test
{
    public static void main(String[] args)
    {
        try {
            foo();
        } catch (StackOverflowError e) {
            bar();
        }
        System.out.println("normal termination");
    }

    private static void foo() {
        System.out.println("foo");
        foo();
    }

    private static void bar() {
        System.out.println("bar");
    }
}

어떻게 이럴 수있어? StackOverflowError가 발생했을 때 스택이 너무 꽉 차서 다른 함수를 호출 할 공간이 없어야한다고 생각합니다. 오류 처리 블록이 다른 스택에서 실행 중입니까? 아니면 여기서 무슨 일이 일어나고 있습니까?



답변

스택이 오버플로 StackOverflowError되어 throw되면 일반적인 예외 처리로 스택이 해제됩니다. 스택을 푸는 것은 다음을 의미합니다.

  • 현재 활성화 된 기능의 실행 중단
  • 스택 프레임을 삭제하고 호출 함수를 진행하십시오.
  • 호출자의 실행 중단
  • 스택 프레임을 삭제하고 호출 함수를 진행하십시오.
  • 등등…

… 예외가 잡힐 때까지. 이것은 정상 (사실 필요)이며 어떤 예외가 발생하고 그 이유와는 무관합니다. 에 대한 첫 번째 호출 외부에서 예외를 포착했기 때문에 스택을 채운 foo()수천 개의 foo스택 프레임이 모두 풀 렸고 대부분의 스택을 다시 사용할 수 있습니다.


답변

StackOverflowError가 발생하면 스택이 가득 찼습니다. 그러나 잡히면 모든 foo호출이 스택에서 팝되었습니다. bar스택이 더 이상 foos로 넘치지 않기 때문에 정상적으로 실행될 수 있습니다 . (JLS가 이와 같은 스택 오버플로에서 복구 할 수 있다고 보장하지 않는다는 점에 유의하십시오.)


답변

StackOverFlow가 발생하면 JVM이 캐치로 팝업되어 스택이 해제됩니다.

당신의 예에서는 모든 스택 foo를 제거합니다.


답변

스택이 실제로 오버플로되지 않기 때문입니다. 더 나은 이름은 AttemptToOverflowStack 일 수 있습니다. 기본적으로 스택 프레임을 조정하려는 마지막 시도는 스택에 충분한 여유 공간이 남아 있지 않기 때문에 오류가 발생한다는 것을 의미합니다. 스택에는 실제로 공간이 충분하지 않고 많은 공간이 남아있을 수 있습니다. 따라서 호출 성공 (일반적으로 메서드 호출)에 의존하는 작업이 무엇이든 예외가 발생하지 않으며 남은 것은 프로그램이 해당 사실을 처리하는 것입니다. 이는 다른 예외와 실제로 다르지 않다는 것을 의미합니다. 실제로 호출하는 함수에서 예외를 포착 할 수 있습니다.


답변

바와 같이 이미 답 ,이 코드를 실행하는 것이 가능하고, 특히 잡는 후, 함수를 호출 할 수 StackOverflowError는 JVM의 절차를 처리하는 일반적인 예외가 사이의 스택 풀릴 때문에 throw하고 catch사용하는 스택 공간을 확보, 점. 그리고 당신의 실험은 그것이 사실임을 확인합니다.

그러나 이는 일반적으로 .NET Framework 에서 복구 할 수 있다고 말하는 것과는 다릅니다 StackOverflowError.

A는 StackOverflowError-A IS VirtualMachineErrorIS-AN, Error. 지적했듯이 Java는 다음에 대한 모호한 조언을 제공합니다 Error.

합리적인 응용 프로그램이 포착하려고 시도해서는 안되는 심각한 문제를 나타냅니다.

그리고 당신은 합리적 으로 어떤 상황에서는 잡는 것이 괜찮을지도 모른다고 생각 해야 한다고 결론을 내립니다 Error. 한 번의 실험을 수행한다고해서 일반적으로 안전하게 수행 할 수있는 작업이 있다는 것을 보여주지는 않습니다. Java 언어의 규칙과 사용하는 클래스의 사양 만이이를 수행 할 수 있습니다. Java 언어 사양Java 가상 머신 사양 이이 예외의 의미에 대한 정보를 제공 VirtualMachineError하기 때문에 A 는 예외의 특수 클래스입니다 . 특히 후자는 다음 과 같이 말합니다 .

Java Virtual Machine 구현 VirtualMethodError은 내부 오류 또는 리소스 제한으로 인해이 장에 설명 된 의미를 구현하지 못하는 경우 클래스의 하위 클래스 인스턴스 인 객체를 throw합니다 . 이 사양은 내부 오류 또는 리소스 제한이 발생할 수있는 위치를 예측할 수 없으며보고 할 수있는시기를 정확하게 지정하지 않습니다. 따라서 VirtualMethodError아래에 정의 된 모든 서브 클래스는 Java Virtual Machine이 작동하는 동안 언제든지 throw 될 수 있습니다.

  • StackOverflowError: Java Virtual Machine 구현은 스레드에 대한 스택 공간이 부족합니다. 일반적으로 스레드가 실행 프로그램의 결함으로 인해 제한되지 않은 수의 재귀 호출을 수행하기 때문입니다.

중요한 문제는 어디에서 언제 StackOverflowError던질 지 “예측할 수 없다”는 것입니다. 던지지 않을 위치에 대한 보장없습니다 . 예를 들어 메소드에 대한 항목 에 던져지는 것에 의존 할 수 없습니다 . 메서드 내의 한 지점 에서 throw 될 수 있습니다 .

이 예측 불가능 성은 잠재적으로 재앙입니다. 메서드 내에서 throw 될 수 있으므로 클래스가 하나의 “원자 적”작업으로 간주하는 일련의 작업을 통해 부분적으로 throw되어 개체가 부분적으로 수정되고 일관성이없는 상태로 남습니다. 개체가 일관성이없는 상태에 있는 경우 해당 개체를 사용하려고하면 잘못된 동작이 발생할 수 있습니다. 모든 실제 경우에 어떤 개체가 일관성이없는 상태 인지 알 수 없으므로 신뢰할 수있는 개체가 없다고 가정해야 합니다. 모든 예외가 때문에 잘못된 행동을 할 수 잡은 후 복구 작업이나 시도는 계속합니다. 할 수있는 유일한 안전한 것은하는 것이다 되지 를 잡을StackOverflowError, 오히려 프로그램이 종료되도록 허용합니다. (실제로 당신은 문제 해결을 돕기 위해 몇 가지 오류 로깅을 시도 할 수 있습니다,하지만 당신은 할 수없는 의존 제대로 작동하는 로깅). 즉, 당신은 안정적으로 복구 할 수 있습니다StackOverflowError .


답변