java.lang.StackOverflowError의 원인


답변:


59

메서드에 대한 반향적인 호출이 있는지 확인하십시오. 주로 메서드에 대한 재귀 호출이있을 때 발생합니다. 간단한 예는

public static void main(String... args) {
    Main main = new Main();

    main.testMethod(1);
}

public void testMethod(int i) {
    testMethod(i);

    System.out.println(i);
}

여기 System.out.println (i); testMethod가 호출되면 스택에 반복적으로 푸시됩니다.


1
그 쪽이 맞는 거 같아요. 그러나 그것의 해결책은 무엇입니까. 우리가 메쏘드를 재사용하고 있기 때문에 그것이 필요하다는 것을 의미합니다. 우리는 방법을 바꾸고 싶지 않습니다. 그렇다면이 오류를 어떻게 해결할 수 있습니까?
아제 샤르마

1
또는 당신은 무한 루프에 들어갑니다!
yalematta

@yalematta, 모든 재귀 메서드에는 종료 조건이 있어야합니다. 따라서 재귀 방법이 제대로 구현되고 일부 조건에 따라 완료되는지 확인하십시오.
Ayaz Alifov

@AjaySharma JVM에 할당 한 사용 가능한 메모리 경계에 맞도록 시스템을 설계해야합니다. 시스템이 다음 오류로 인해 어색하게 작동하면 코드베이스를 확인해야합니다.
Thota Srinath 2017-06-15

22

JVM에 대한 (선택적) 인수 중 하나는 스택 크기입니다. -Xss입니다. 기본값이 무엇인지 모르겠지만 스택에있는 항목의 총량이 해당 값을 초과하면 해당 오류가 발생합니다.

일반적으로 무한 재귀가 원인이지만,이를 확인했다면 스택 추적에 5 개 이상의 프레임이있을 것입니다.

-Xss 인수를 추가 (또는 1의 값 증가)하여 이것이 사라지는 지 확인하십시오.


10

실제로 java.lang.StackOverflowError의 원인은 일반적으로 의도하지 않은 재귀입니다. 저에게는 종종 오버라이드 된 메서드에 대해 슈퍼 메서드를 호출하려고 할 때입니다. 이 경우와 같이 :

public class Vehicle {
    public void accelerate(float acceleration, float maxVelocity) {
        // set the acceleration
    }
}

public class SpaceShip extends Vehicle {
    @Override
    public void accelerate(float acceleration, float maxVelocity) {
        // update the flux capacitor and call super.accelerate
        // oops meant to call super.accelerate(acceleration, maxVelocity);
        // but accidentally wrote this instead. A StackOverflow is in our future.
        this.accelerate(acceleration, maxVelocity); 
    }
}

첫째, 함수를 호출 할 때 뒤에서 일어나는 일을 아는 것이 유용합니다. 메서드가 호출 된 인수와 주소는 스택에 푸시 되므로 ( http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management 참조 ) 호출 된 메서드가 인수에 액세스 할 수 있습니다. 호출 된 메서드가 완료되면 호출 후 실행을 계속할 수 있습니다. 그러나 우리는 this.accelerate (acceleration, maxVelocity)를 재귀 적으로 호출하기 때문에 (재귀는 메서드가 스스로를 호출 할 때 느슨합니다. 자세한 내용은 http://en.wikipedia.org/wiki/Recursion_(computer_science)를 참조하십시오 .) 우리는 무한 재귀로 알려진 상황에 처해 있으며 인수를 계속 쌓고 호출 스택에 주소를 반환합니다. 호출 스택의 크기가 한정되어 있으므로 결국 공간이 부족합니다. 호출 스택의 공간 부족을 오버플로라고합니다. 이것은 우리가 가지고있는 것보다 더 많은 스택 공간을 사용하려고하고 데이터가 말 그대로 스택을 오버플로하기 때문입니다. Java 프로그래밍 언어에서 이로 인해 런타임 예외 java.lang.StackOverflow가 발생하고 프로그램이 즉시 중지됩니다.

위의 예는 다소 단순화되어 있습니다 (하지만 제가 인정하고 싶은 것보다 더 많이 발생합니다.) 동일한 일이 더 많은 방식으로 발생하여 추적하기가 조금 더 어려워 질 수 있습니다. 그러나 일반적으로 StackOverflow는 일반적으로 일단 발생하면 해결하기가 매우 쉽습니다.

이론적으로는 재귀없이 스택 오버플로가 발생할 수도 있지만 실제로는 매우 드문 이벤트 인 것처럼 보입니다.


8

뭐가 java.lang.StackOverflowError

이 오류 java.lang.StackOverflowError는 깊은 재귀로 인해 응용 프로그램의 스택이 고갈되었음을 나타 내기 위해 발생합니다. 즉, 프로그램 / 스크립트가 너무 많이 반복됩니다.

세부

StackOverflowError확장 VirtualMachineErrorJVM이 있었다 또는 자원이 부족하고 할 수있는 더 작동하지 나타냅니다 클래스를. VirtualMachineError확장하는 Error클래스는 응용 프로그램이 잡을해야하는 심각한 문제를 나타내는 데 사용됩니다. 메서드는 이러한 오류를 선언 할 수 없습니다.throw이러한 오류는 발생하지 않을 것으로 예상되는 비정상적인 조건이므로 절 .

Minimal, Complete, and Verifiable Example :

package demo;

public class StackOverflowErrorExample {

    public static void main(String[] args) 
    {
        StackOverflowErrorExample.recursivePrint(1);
    }

    public static void recursivePrint(int num) {
        System.out.println("Number: " + num);

        if(num == 0)
            return;
        else
            recursivePrint(++num);
    }

}

콘솔 출력

Number: 1
Number: 2
.
.
.
Number: 8645
Number: 8646
Number: 8647Exception in thread "main" java.lang.StackOverflowError
    at java.io.FileOutputStream.write(Unknown Source)
    at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
    at java.io.BufferedOutputStream.flush(Unknown Source)
    at java.io.PrintStream.write(Unknown Source)
    at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
    at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
    at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
    at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
    at java.io.PrintStream.newLine(Unknown Source)
    at java.io.PrintStream.println(Unknown Source)
    at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:11)
    at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)
    .
    .
    .
    at demo.StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:16)

설명

Java 애플리케이션이 함수 호출을 호출하면 스택 프레임호출 스택 에 할당됩니다 . 는 stack frame호출 된 메소드, 로컬 매개 변수와 메소드의 반환 주소의 매개 변수가 포함되어 있습니다. 반환 주소는 호출 된 메서드가 반환 된 후 프로그램 실행이 계속되는 실행 지점을 나타냅니다. 새 스택 프레임을위한 공간이 없으면 StackOverflowErrorJVM (Java Virtual Machine)에서을 처리합니다.

Java 애플리케이션의 스택을 소진시킬 수있는 가장 일반적인 경우는 재귀입니다. 재귀에서 메서드는 실행 중에 자신을 호출합니다. Recursion가장 강력한 범용 프로그래밍 기술 중 하나이지만 StackOverflowError이를 방지 하려면주의해서 사용해야합니다 .

참고 문헌


4

Java 애플리케이션에서 함수 호출을 호출하면 스택 프레임이 호출 스택에 할당됩니다. 스택 프레임에는 호출 된 메서드의 매개 변수, 로컬 매개 변수 및 메서드의 반환 주소가 포함됩니다.

반환 주소는 호출 된 메서드가 반환 된 후 프로그램 실행이 계속되는 실행 지점을 나타냅니다. 새 스택 프레임을위한 공간이 없으면 JVM (Java Virtual Machine) 에서 StackOverflowError 가 발생합니다. .

Java 애플리케이션의 스택을 소진시킬 수있는 가장 일반적인 경우는 재귀입니다.

한번 봐주세요

StackOverflowError를 해결하는 방법


3

데이터를 구문 분석 할 때 Hibernate 사용자를위한 솔루션 :

나는 양쪽에 매핑 된 개체의 목록을 구문 분석했기 때문에 나는이 오류를했다 @OneToMany@ManyToOne 무한 루프를 일으킨 jackson을 사용하여 json 가 발생했습니다.

이 같은 상황에있는 경우 사용하여이 문제를 해결할 수 @JsonManagedReference@JsonBackReference 주석 .

API의 정의 :

  • JsonManagedReference ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html ) :

    주석이 달린 속성이 필드 간 양방향 연결의 일부임을 나타내는 데 사용되는 주석입니다. 그 역할은 "부모"(또는 "앞으로") 링크입니다. 속성의 값 유형 (클래스)에는 JsonBackReference로 주석이 달린 호환 가능한 단일 속성이 있어야합니다. 연결은이 주석으로 주석이 달린 속성이 정상적으로 처리되도록 처리됩니다 (일반적으로 직렬화되고 역 직렬화에 대한 특수 처리 없음). 특수 처리가 필요한 일치하는 역 참조입니다.

  • JsonBackReference : ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html ) :

    연관된 속성이 필드 간의 양방향 연결의 일부임을 나타내는 데 사용되는 주석입니다. 그 역할은 "하위"(또는 "뒤로") 링크입니다. 속성의 값 유형은 빈이어야합니다. 컬렉션, 맵, 배열 또는 열거가 될 수 없습니다. 이 어노테이션으로 어노테이션이있는 특성이 직렬화되지 않도록 링크가 처리됩니다. deserialization 중에 해당 값은 "관리"(정방향) 링크가있는 인스턴스로 설정됩니다.

예:

Owner.java :

@JsonManagedReference
@OneToMany(mappedBy = "owner", fetch = FetchType.EAGER)
Set<Car> cars;

Car.java :

@JsonBackReference
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "owner_id")
private Owner owner;

또 다른 해결책은 @JsonIgnore필드에 null을 설정하는 것을 사용 하는 것입니다.


2

나는 Hibernate로 프로그램을 만들었는데, 여기서 두 개의 POJO 클래스를 만들었는데, 둘 다 데이터 멤버로서 서로의 객체를 가지고 있었다. 주요 방법에서 데이터베이스에 저장하려고 할 때도이 오류가 발생했습니다.

이것은 두 클래스가 서로를 참조하기 때문에 발생하므로이 오류를 일으키는 루프가 생성됩니다.

따라서 프로그램에 이러한 종류의 관계가 있는지 확인하십시오.


1

스택 오버플로 예외는 스레드 스택이 최대 제한에 도달 할 때까지 크기가 계속 증가 할 때 발생할 수 있습니다.

스택 크기 (Xss 및 Xmso) 옵션 조정 ...

: 나는 당신이이 링크를 참조 제안 http://www-01.ibm.com/support/docview.wss?uid=swg21162896을 ....하지 않고 StackOverflowError 많은 원인이 있습니다이 링크에서 볼 수 있듯이,


링크 전용 답변은 일반적으로 허용되지 않습니다. 링크가 끊어지면 답이 완전히 무효화됩니다. 링크 대신 답변에 대한 컨텍스트, 코드 및 설명을 제공하십시오.
Jay

0

제 경우에는 두 가지 활동이 있습니다. 두 번째 활동에서 나는 onCreate 메소드에 super를 넣는 것을 잊었습니다.

super.onCreate(savedInstanceState);

를 제기 할 수있는 방법 StackOverflowError이라고해도 질문에 답하고 있다고 생각하지 않습니다. 나는 적절한 대답이 너무 많은 재귀를 사용하는 것 보다이 예외를 얻는 다른 방법을 나열하거나 수동으로 던지는 것 외에는 그러한 예외를 얻는 다른 방법이 없다고 말해야한다고 생각합니다.
JojOatXGME
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.