Java.lang.StackOverflowError
の原因は何ですか?私が取得するスタックの印刷は、まったく深くありません(5つのメソッドのみ)。
メソッドの異常な呼び出しを確認します。主に、メソッドの再帰呼び出しがある場合に発生します。簡単な例は
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が呼び出されると、スタックに繰り返しプッシュされます。
JVMの(オプションの)引数の1つはスタックサイズです。 -Xssです。デフォルト値が何かわかりませんが、スタックの総量がその値を超えると、そのエラーが発生します。
一般に、無限再帰がこの原因です。しかし、それを見た場合、スタックトレースには5フレーム以上あります。
-Xss引数を追加(または1の値を増やす)して、これがなくなるかどうかを確認してください。
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は通常、発生すると簡単に解決できます。
理論的には、再帰なしでスタックオーバーフローが発生することもありますが、実際には、かなりまれなイベントのように見えます。
Java.lang.StackOverflowError
とはエラーJava.lang.StackOverflowError
は、深い再帰、つまりプログラム/スクリプトの再帰が深すぎるために、アプリケーションのスタックが使い果たされたことを示すためにスローされます。
StackOverflowError
はVirtualMachineError
クラスを拡張します。これは、JVMがリソースを使い果たした、または使い果たし、それ以上操作できないことを示します。 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
には、呼び出されたメソッドのパラメーター、そのローカルパラメーター、およびメソッドの戻りアドレスが含まれます。戻りアドレスは、呼び出されたメソッドが戻った後、プログラムの実行を継続する実行ポイントを示します。新しいスタックフレーム用のスペースがない場合、StackOverflowError
がJava Virtual Machine(JVM)によってスローされます。
Javaアプリケーションのスタックを使い果たす可能性のある最も一般的なケースは、再帰です。再帰では、メソッドは実行中に自身を呼び出します。 Recursion
最も強力な汎用プログラミング手法の1つですが、StackOverflowError
が回避されるように注意して使用する必要があります。
関数呼び出しがJavaアプリケーションによって呼び出されると、スタックフレームが呼び出しスタックに割り当てられます。スタックフレームには、呼び出されたメソッドのパラメーター、そのローカルパラメーター、およびメソッドの戻りアドレスが含まれます。
戻りアドレスは、呼び出されたメソッドが戻った後、プログラムの実行を継続する実行ポイントを示します。新しいスタックフレーム用のスペースがない場合、 StackOverflowError がJava Virtual Machine(JVM)。
Javaアプリケーションのスタックを使い果たす可能性がある最も一般的なケースは、再帰です。
ご覧ください
Hibernateを使用してプログラムを作成しました。このプログラムでは、2つのPOJOクラスを作成し、両方ともデータメンバとして互いのオブジェクトを使用しました。 mainメソッドでデータベースに保存しようとすると、このエラーも発生しました。
これは、両方のクラスが相互に参照しているために発生し、このエラーの原因となるループが作成されます。
そのため、そのような種類の関係がプログラムに存在するかどうかを確認してください。
スタックオーバーフローの例外は、スレッドスタックのサイズが最大制限に達するまで拡大し続けると発生する可能性があります。
スタックサイズ(XssおよびXmso)オプションの調整...
次のリンクを参照することをお勧めします: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 多くの可能性がありますリンクで見ることができるように、StackOverflowErrorの原因となります。
データを解析する際のHibernateユーザー向けのソリューション:
このエラーが発生したのは、無限ループを引き起こしたjacksonを使用して@OneToMany
および@ManyToOne
の両側で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 ):
関連するプロパティがフィールド間の双方向リンケージの一部であることを示すために使用される注釈。そしてその役割は「子」(または「戻る」)リンクであること。プロパティの値の型はBeanである必要があります。Collection、Map、Array、または列挙型にすることはできません。リンケージは、このアノテーションが付けられたプロパティがシリアル化されないように処理されます。逆シリアル化中に、その値は「管理された」(フォワード)リンクを持つインスタンスに設定されます。
例:
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;
別の解決策は、フィールドにnullを設定する@JsonIgnore
を使用することです。
私の場合、2つのアクティビティがあります。 2番目のアクティビティでは、onCreateメソッドにスーパーを配置するのを忘れました。
super.onCreate(savedInstanceState);