O que pode causar um java.lang.StackOverflowError
? A impressão da pilha que obtenho não é muito profunda (apenas 5 métodos).
Respostas:
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.
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.
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.
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.
A classe StackOverflowError
extends VirtualMachineError
que indica que a JVM está ou ficou sem recursos e não pode operar mais. O VirtualMachineError
que estende a Error
classe é 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 throw
cláusula porque esses erros são condições anormais que nunca foram esperadas.
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)
Quando uma chamada de função é invocada por um aplicativo Java, um frame de pilha é alocado na pilha de chamadas . O stack frame
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. Na recursão, um método invoca a si mesmo durante sua execução. Recursion
uma das mais poderosas técnicas de programação de uso geral, mas deve ser usada com cautela, para StackOverflowError
que seja evitada.
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
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 @OneToMany
e @ManyToOne
para json usando jackson, o que causou um loop infinito.
Se você estiver na mesma situação, pode resolver isso usando @JsonManagedReference
e as @JsonBackReference
anotaçõ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 @JsonIgnore
que apenas definirá nulo para o campo.
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.
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 ....
No meu caso, tenho duas atividades. Na segunda atividade esqueci de colocar super no método onCreate.
super.onCreate(savedInstanceState);
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.