Apa yang bisa menyebabkan a java.lang.StackOverflowError
? Hasil cetakan stack yang saya dapatkan tidak terlalu dalam sama sekali (hanya 5 metode).
Jawaban:
Periksa panggilan yang menyimpang untuk metode. Terutama disebabkan ketika ada panggilan rekursif untuk suatu metode. Contoh sederhananya adalah
public static void main(String... args) {
Main main = new Main();
main.testMethod(1);
}
public void testMethod(int i) {
testMethod(i);
System.out.println(i);
}
Di sini System.out.println (i); akan berulang kali didorong ke stack saat testMethod dipanggil.
Salah satu argumen (opsional) untuk JVM adalah ukuran tumpukan. Ini -Xss. Saya tidak tahu apa nilai defaultnya, tetapi jika jumlah total barang di tumpukan melebihi nilai itu, Anda akan mendapatkan kesalahan itu.
Umumnya, rekursi tak terbatas adalah penyebabnya, tetapi jika Anda melihatnya, pelacakan tumpukan Anda akan memiliki lebih dari 5 bingkai.
Coba tambahkan argumen -Xss (atau tingkatkan nilainya) untuk melihat apakah ini hilang.
Apa yang sebenarnya menyebabkan java.lang.StackOverflowError biasanya merupakan rekursi yang tidak disengaja. Bagi saya, sering kali saya bermaksud memanggil metode super untuk metode terlarang. Seperti dalam kasus ini:
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);
}
}
Pertama, sangat berguna untuk mengetahui apa yang terjadi di balik layar saat kita memanggil suatu fungsi. Argumen dan alamat tempat metode dipanggil didorong pada tumpukan (lihat http://en.wikipedia.org/wiki/Stack_(abstract_data_type)#Runtime_memory_management ) sehingga metode yang dipanggil dapat mengakses argumen dan metode yang dipanggil selesai, eksekusi dapat dilanjutkan setelah panggilan. Tapi karena kita memanggil this.accelerate (acceleration, maxVelocity) secara rekursif (rekursi longgar saat metode memanggil dirinya sendiri. Untuk info lebih lanjut lihat http://en.wikipedia.org/wiki/Recursion_(computer_science)) kita berada dalam situasi yang dikenal sebagai rekursi tak terbatas dan kita terus menumpuk argumen dan alamat pengirim pada tumpukan panggilan. Karena tumpukan panggilan berukuran terbatas, kami akhirnya kehabisan ruang. Kehabisan ruang pada tumpukan panggilan dikenal sebagai luapan. Ini karena kami mencoba menggunakan lebih banyak ruang tumpukan daripada yang kami miliki dan data benar-benar meluap dari tumpukan. Dalam bahasa pemrograman Java, ini menghasilkan pengecualian runtime java.lang.StackOverflow dan akan segera menghentikan program.
Contoh di atas agak disederhanakan (meskipun itu terjadi pada saya lebih dari yang ingin saya akui.) Hal yang sama dapat terjadi secara lebih bulat tentang cara membuatnya sedikit lebih sulit untuk dilacak. Namun, secara umum, StackOverflow biasanya cukup mudah diatasi, setelah terjadi.
Secara teori, dimungkinkan juga untuk memiliki stack overflow tanpa rekursi, tetapi dalam praktiknya, ini tampaknya merupakan peristiwa yang cukup langka.
java.lang.StackOverflowError
Kesalahan ditampilkan java.lang.StackOverflowError
untuk menunjukkan bahwa tumpukan aplikasi telah habis, karena rekursi yang dalam, yaitu program / skrip Anda berulang terlalu dalam.
Kelas StackOverflowError
extends VirtualMachineError
yang menunjukkan bahwa JVM telah atau telah kehabisan sumber daya dan tidak dapat beroperasi lebih lanjut. Kelas VirtualMachineError
yang meluas Error
digunakan untuk menunjukkan masalah serius yang tidak boleh ditangkap oleh aplikasi. Metode mungkin tidak mendeklarasikan kesalahan seperti itu dalam throw
klausulnya karena kesalahan ini adalah kondisi abnormal yang tidak pernah diharapkan terjadi.
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)
Saat panggilan fungsi dipanggil oleh Aplikasi Java, frame stack dialokasikan pada stack panggilan . The stack frame
berisi parameter dari metode dipanggil, parameter lokal, dan alamat pengirim dari metode ini. Alamat pengirim menunjukkan titik eksekusi dari mana, eksekusi program harus dilanjutkan setelah metode yang dipanggil kembali. Jika tidak ada ruang untuk bingkai tumpukan baru, maka StackOverflowError
akan dilempar oleh Java Virtual Machine (JVM).
Kasus paling umum yang mungkin dapat menghabiskan tumpukan aplikasi Java adalah rekursi. Dalam rekursi, metode memanggil dirinya sendiri selama eksekusinya. Recursion
salah satu teknik pemrograman tujuan umum yang paling kuat, tetapi harus digunakan dengan hati-hati, agar hal StackOverflowError
itu dihindari.
Saat panggilan fungsi dipanggil oleh aplikasi Java, frame stack dialokasikan pada stack panggilan. Bingkai tumpukan berisi parameter metode yang dipanggil, parameter lokalnya, dan alamat kembalian metode tersebut.
Alamat pengirim menunjukkan titik eksekusi dari mana, eksekusi program harus dilanjutkan setelah metode yang dipanggil kembali. Jika tidak ada ruang untuk bingkai tumpukan baru, StackOverflowError dilemparkan oleh Java Virtual Machine (JVM) .
Kasus paling umum yang mungkin dapat menghabiskan tumpukan aplikasi Java adalah rekursi.
Mohon dilihat
Solusi untuk pengguna Hibernate saat mengurai data:
Saya mengalami kesalahan ini karena saya sedang mengurai daftar objek yang dipetakan di kedua sisi @OneToMany
dan @ManyToOne
ke json menggunakan jackson yang menyebabkan pengulangan tak terbatas.
Jika Anda berada dalam situasi yang sama, Anda dapat menyelesaikannya dengan menggunakan anotasi @JsonManagedReference
dan @JsonBackReference
.
Definisi dari API:
JsonManagedReference ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonManagedReference.html ):
Anotasi digunakan untuk menunjukkan bahwa properti beranotasi adalah bagian dari hubungan dua arah antar bidang; dan perannya adalah tautan "induk" (atau "penerusan"). Jenis nilai (kelas) properti harus memiliki satu properti kompatibel yang dianotasi dengan JsonBackReference. Tautan ditangani sedemikian rupa sehingga properti yang dianotasi dengan anotasi ini ditangani secara normal (berseri secara normal, tidak ada penanganan khusus untuk deserialisasi); itu adalah referensi pencocokan kembali yang memerlukan penanganan khusus
JsonBackReference: ( https://fasterxml.github.io/jackson-annotations/javadoc/2.5/com/fasterxml/jackson/annotation/JsonBackReference.html ):
Anotasi digunakan untuk menunjukkan bahwa properti terkait adalah bagian dari hubungan dua arah antar bidang; dan perannya adalah tautan "anak" (atau "kembali"). Jenis nilai properti harus berupa kacang: tidak dapat berupa Koleksi, Peta, Array, atau pencacahan. Tautan ditangani sedemikian rupa sehingga properti yang dianotasi dengan anotasi ini tidak berseri; dan selama deserialisasi, nilainya disetel ke instance yang memiliki tautan "terkelola" (meneruskan).
Contoh:
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;
Solusi lain adalah menggunakan @JsonIgnore
yang hanya akan menetapkan nol ke lapangan.
Saya membuat program dengan hibernate, di mana saya membuat dua kelas POJO, keduanya dengan objek satu sama lain sebagai anggota data. Ketika dalam metode utama saya mencoba menyimpannya di database, saya juga mendapat kesalahan ini.
Hal ini terjadi karena kedua kelas saling merujuk, sehingga membuat perulangan yang menyebabkan kesalahan ini.
Jadi, periksa apakah ada jenis hubungan seperti itu dalam program Anda.
Pengecualian Stack Overflow dapat terjadi jika ukuran tumpukan benang terus bertambah hingga mencapai batas maksimum.
Menyesuaikan opsi Stack Sizes (Xss dan Xmso) ...
Saya sarankan Anda melihat tautan ini: http://www-01.ibm.com/support/docview.wss?uid=swg21162896 Ada banyak kemungkinan penyebab StackOverflowError, seperti yang Anda lihat di tautan ....
Dalam kasus saya, saya memiliki dua aktivitas. Pada aktivitas kedua saya lupa menempatkan super pada metode onCreate.
super.onCreate(savedInstanceState);
StackOverflowError
, saya tidak berpikir itu menjawab pertanyaan. Saya pikir jawaban yang tepat harus mencantumkan cara lain untuk mendapatkan pengecualian ini daripada menggunakan terlalu banyak rekursi atau mengatakan bahwa pasti tidak ada cara lain untuk mendapatkan pengecualian seperti itu kecuali dengan melemparkannya secara manual.