何が原因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が呼び出されると、スタックに繰り返しプッシュされます。
実際に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仮想マシン(JVM)によってスローされます。
Javaアプリケーションのスタックを使い果たす可能性がある最も一般的なケースは、再帰です。再帰では、メソッドは実行中にそれ自体を呼び出します。Recursion
最も強力な汎用プログラミング手法の1つですが、StackOverflowError
回避するために注意して使用する必要があります。
Javaアプリケーションによって関数呼び出しが呼び出されると、スタックフレームが呼び出しスタックに割り当てられます。スタックフレームには、呼び出されたメソッドのパラメーター、そのローカルパラメーター、およびメソッドの戻りアドレスが含まれています。
戻りアドレスは、呼び出されたメソッドが戻った後もプログラムの実行を続行する実行ポイントを示します。新しいスタックフレーム用のスペースがない場合、StackOverflowErrorはJava仮想マシン(JVM)によってスローされます。
Javaアプリケーションのスタックを使い果たす可能性がある最も一般的なケースは、再帰です。
ご覧ください
データを解析する際のHibernateユーザー向けのソリューション:
両側@OneToMany
と@ManyToOne
jsonにマップされたオブジェクトのリストをjacksonを使用して解析していたため、このエラーが発生し、無限ループが発生しました。
同じ状況にある場合は@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である必要があります。コレクション、マップ、配列、または列挙型にすることはできません。リンケージは、このアノテーションが付けられたプロパティがシリアル化されないように処理されます。逆シリアル化中、その値は「マネージド」(フォワード)リンクを持つインスタンスに設定されます。
例:
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を設定するだけのを使用することです。
スタックオーバーフローの例外は、スレッドスタックが最大制限に達するまでサイズが大きくなり続けると発生する可能性があります。
スタックサイズ(XssおよびXmso)オプションの調整...
次のリンクを参照することをお勧めします。http: //www-01.ibm.com/support/docview.wss?uid = swg21162896リンクに 示されているように、StackOverflowErrorには多くの原因が考えられます。
私の場合、2つの活動があります。2番目のアクティビティでは、onCreateメソッドにスーパーを置くのを忘れました。
super.onCreate(savedInstanceState);
StackOverflowError
、私はそれが質問に答えているとは思いません。適切な答えは、再帰を多用する以外にこの例外を取得する他の方法をリストするか、手動でスローする以外にそのような例外を取得する他の方法は絶対にないと言うべきだと思います。