O que causa um java.lang.StackOverflowError

Respostas:

59

Verifique se há chamadas recusivas para métodos. Principalmente, é causado quando há uma chamada recursiva para um método. Um exemplo simples é

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

    main.testMethod(1);
}

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

    System.out.println(i);
}

Aqui, o System.out.println (i); será repetidamente empurrado para a pilha quando o testMethod for chamado.

Thota Srinath
fonte
1
Eu acho que você está certo. Mas qual é a solução disso. Porque estamos criando um método que impede que isso signifique que precisamos disso. Não queremos fazer mudanças no método. Então, como posso resolver esse erro?
Ajay Sharma de
1
ou você está entrando em um loop infinito!
yalematta de
@yalematta, qualquer método recursivo deve ter uma condição para sair. Portanto, verifique se o seu método recursivo está implementado corretamente e termina dependendo de alguma condição.
Ayaz Alifov
@AjaySharma Precisamos projetar nosso sistema para caber nos limites de memória disponíveis que atribuímos à JVM. Se o sistema se comportar de maneira estranha com o seguinte erro, precisamos verificar nossa base de código.
Thota Srinath de
23

Um dos argumentos (opcionais) para a JVM é o tamanho da pilha. É -Xss. Não sei qual é o valor padrão, mas se a quantidade total de coisas na pilha exceder esse valor, você obterá esse erro.

Geralmente, recursão infinita é a causa disso, mas se você estivesse vendo isso, o rastreamento de pilha teria mais de 5 quadros.

Tente adicionar um argumento -Xss (ou aumentar o valor de um) para ver se isso desaparece.

nsayer
fonte
10

O que realmente causa um java.lang.StackOverflowError é normalmente a recursão não intencional. Para mim, é frequentemente quando pretendo chamar um super método para o método substituído. Como neste caso:

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); 
    }
}

Primeiro, é útil saber o que acontece nos bastidores quando chamamos uma função. Os argumentos e o endereço de onde o método foi chamado são colocados na pilha (consulte http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management ) para que o método chamado possa acessar os argumentos e para que quando o método chamado for concluído, a execução pode continuar após a chamada. Mas como estamos chamando this.accelerate (acceleration, maxVelocity) recursivamente (a recursão ocorre vagamente quando um método chama a si mesmo. Para obter mais informações, consulte http://en.wikipedia.org/wiki/Recursion_(computer_science)) estamos em uma situação conhecida como recursão infinita e continuamos empilhando os argumentos e o endereço de retorno na pilha de chamadas. Como a pilha de chamadas tem tamanho finito, eventualmente ficamos sem espaço. A falta de espaço na pilha de chamadas é conhecida como estouro. Isso ocorre porque estamos tentando usar mais espaço de pilha do que temos e os dados literalmente estouram a pilha. Na linguagem de programação Java, isso resulta na exceção de tempo de execução java.lang.StackOverflow e interromperá imediatamente o programa.

O exemplo acima é um tanto simplificado (embora isso aconteça comigo mais do que eu gostaria de admitir). A mesma coisa pode acontecer de uma maneira mais geral, tornando-o um pouco mais difícil de rastrear. No entanto, em geral, o StackOverflow é geralmente muito fácil de resolver, uma vez que ocorre.

Em teoria, também é possível ter um estouro de pilha sem recursão, mas na prática, parece ser um evento bastante raro.

ptoinson
fonte
8

O que é java.lang.StackOverflowError

O erro java.lang.StackOverflowErroré lançado para indicar que a pilha do aplicativo foi esgotada, devido à recursão profunda, ou seja, seu programa / script recorre muito profundamente.

Detalhes

A classe StackOverflowErrorextends VirtualMachineErrorque indica que a JVM está ou ficou sem recursos e não pode operar mais. O VirtualMachineErrorque estende a Errorclasse é usado para indicar os problemas sérios que um aplicativo não deve detectar. Um método não pode declarar esses erros em sua throwcláusula porque esses erros são condições anormais que nunca foram esperadas.

Um exemplo

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);
    }

}

Saída do console

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)

Explicação

Quando uma chamada de função é invocada por um aplicativo Java, um frame de pilha é alocado na pilha de chamadas . O stack framecontém os parâmetros do método invocado, seus parâmetros locais e o endereço de retorno do método. O endereço de retorno denota o ponto de execução a partir do qual a execução do programa deve continuar após o retorno do método invocado. Se não houver espaço para um novo quadro de pilha, o StackOverflowErrorserá lançado pela Java Virtual Machine (JVM).

O caso mais comum que pode esgotar a pilha de um aplicativo Java é a recursão. Na recursão, um método invoca a si mesmo durante sua execução. Recursionuma das mais poderosas técnicas de programação de uso geral, mas deve ser usada com cautela, para StackOverflowErrorque seja evitada.

Referências

DebanjanB
fonte
4

Quando uma chamada de função é invocada por um aplicativo Java, um quadro de pilha é alocado na pilha de chamadas. O quadro de pilha contém os parâmetros do método invocado, seus parâmetros locais e o endereço de retorno do método.

O endereço de retorno denota o ponto de execução a partir do qual a execução do programa deve continuar após o retorno do método invocado. Se não houver espaço para um novo quadro de pilha, o StackOverflowError será lançado pela Java Virtual Machine (JVM) .

O caso mais comum que pode esgotar a pilha de um aplicativo Java é a recursão.

Por favor, dê uma olhada

Como resolver StackOverflowError

IntelliJ Amiya
fonte
3

Solução para usuários do Hibernate ao analisar dados:

Eu tive esse erro porque estava analisando uma lista de objetos mapeados em ambos os lados @OneToManye @ManyToOnepara json usando jackson, o que causou um loop infinito.

Se você estiver na mesma situação, pode resolver isso usando @JsonManagedReferencee as @JsonBackReferenceanotações.

Definições da API:

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

    Anotação usada para indicar que a propriedade anotada faz parte de uma ligação bidirecional entre os campos; e que sua função é o link "pai" (ou "encaminhamento"). O tipo de valor (classe) da propriedade deve ter uma única propriedade compatível anotada com JsonBackReference. A vinculação é tratada de forma que a propriedade anotada com essa anotação seja tratada normalmente (serializada normalmente, sem tratamento especial para desserialização); é a referência anterior correspondente que requer tratamento especial

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

    Anotação usada para indicar que a propriedade associada faz parte de uma ligação bidirecional entre os campos; e que sua função é o link "filho" (ou "de volta"). O tipo de valor da propriedade deve ser um bean: não pode ser uma Coleção, Mapa, Matriz ou enumeração. A ligação é tratada de forma que a propriedade anotada com esta anotação não seja serializada; e durante a desserialização, seu valor é definido para a instância que possui o link "gerenciado" (encaminhamento).

Exemplo:

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;

Outra solução é usar @JsonIgnoreque apenas definirá nulo para o campo.

Emerica
fonte
2

Criei um programa com hibernate, no qual criei duas classes POJO, ambas com um objeto uma da outra como membros de dados. Quando no método principal tentei salvá-los no banco de dados também obtive este erro.

Isso acontece porque as duas classes estão se referindo uma à outra, criando, portanto, um loop que causa esse erro.

Portanto, verifique se esse tipo de relacionamento existe em seu programa.

Singh
fonte
1

As exceções de estouro de pilha podem ocorrer quando uma pilha de encadeamentos continua a crescer em tamanho até atingir o limite máximo.

Ajustando as opções de tamanhos de pilha (Xss e Xmso) ...

Eu sugiro que você veja este link: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Existem muitas causas possíveis para um StackOverflowError, como você pode ver no link ....

Marzieh Ghadirinia
fonte
Geralmente, as respostas apenas com links não são aceitáveis; links quebrados, o que invalidaria totalmente a resposta. Forneça algum contexto, código e uma explicação da resposta em vez de apenas um link.
Jay,
0

No meu caso, tenho duas atividades. Na segunda atividade esqueci de colocar super no método onCreate.

super.onCreate(savedInstanceState);
Julz Etnalob
fonte
Mesmo que seja uma forma possível de levantar um StackOverflowError, não creio que esteja respondendo à pergunta. Acho que uma resposta adequada deve listar outras maneiras de obter essa exceção, além de usar muita recursão, ou dizer que definitivamente não há outra maneira de obter essa exceção, exceto lançá-la manualmente.
JojOatXGME