Untuk menggambarkan ini, pertama mari kita pahami bagaimana variabel dan objek lokal disimpan.
Variabel lokal disimpan dalam tumpukan :
Jika Anda melihat gambar Anda harus dapat memahami bagaimana segala sesuatunya bekerja.
Ketika panggilan fungsi dipanggil oleh aplikasi Java, bingkai tumpukan dialokasikan pada tumpukan panggilan. Bingkai tumpukan berisi parameter dari metode yang dipanggil, parameter lokalnya, dan alamat pengembalian metode. Alamat kembali menunjukkan titik eksekusi dari mana, eksekusi program akan dilanjutkan setelah metode yang dipanggil kembali. Jika tidak ada ruang untuk bingkai tumpukan baru, maka StackOverflowError
dilemparkan oleh Java Virtual Machine (JVM).
Kasus paling umum yang mungkin dapat menghabiskan tumpukan aplikasi Java adalah rekursi. Dalam rekursi, metode memanggil dirinya sendiri selama eksekusi. Rekursi dianggap sebagai teknik pemrograman tujuan umum yang kuat tetapi harus digunakan dengan hati-hati, untuk menghindari StackOverflowError
.
Contoh melempar a StackOverflowError
ditunjukkan di bawah ini:
StackOverflowErrorExample.java:
public class StackOverflowErrorExample {
public static void recursivePrint(int num) {
System.out.println("Number: " + num);
if (num == 0)
return;
else
recursivePrint(++num);
}
public static void main(String[] args) {
StackOverflowErrorExample.recursivePrint(1);
}
}
Dalam contoh ini, kami mendefinisikan metode rekursif, yang disebut recursivePrint
yang mencetak bilangan bulat dan kemudian, memanggil dirinya sendiri, dengan bilangan bulat berikutnya sebagai argumen. Rekursi berakhir sampai kita lulus 0
sebagai parameter. Namun, dalam contoh kami, kami meneruskan dalam parameter dari 1 dan peningkatan pengikut, akibatnya, rekursi tidak akan pernah berakhir.
Eksekusi sampel, menggunakan -Xss1M
bendera yang menentukan ukuran tumpukan ulir sama dengan 1MB, ditunjukkan di bawah ini:
Number: 1
Number: 2
Number: 3
...
Number: 6262
Number: 6263
Number: 6264
Number: 6265
Number: 6266
Exception in thread "main" java.lang.StackOverflowError
at java.io.PrintStream.write(PrintStream.java:480)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
at java.io.PrintStream.write(PrintStream.java:527)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:806)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:4)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
at StackOverflowErrorExample.recursivePrint(StackOverflowErrorExample.java:9)
...
Tergantung pada konfigurasi awal JVM, hasilnya mungkin berbeda, tetapi akhirnya StackOverflowError
harus dibuang. Contoh ini adalah contoh yang sangat baik tentang bagaimana rekursi dapat menyebabkan masalah, jika tidak diterapkan dengan hati-hati.
Cara menangani StackOverflowError
Solusi paling sederhana adalah dengan hati-hati memeriksa jejak tumpukan dan mendeteksi pola pengulangan nomor garis. Nomor-nomor baris ini menunjukkan kode yang dipanggil secara rekursif. Setelah Anda mendeteksi garis-garis ini, Anda harus hati-hati memeriksa kode Anda dan memahami mengapa rekursi tidak pernah berakhir.
Jika Anda telah memverifikasi bahwa rekursi diimplementasikan dengan benar, Anda dapat meningkatkan ukuran tumpukan, untuk memungkinkan jumlah doa yang lebih besar. Bergantung pada Java Virtual Machine (JVM) yang diinstal, ukuran tumpukan ulir default mungkin sama dengan 512KB, atau 1MB . Anda dapat meningkatkan ukuran tumpukan ulir menggunakan -Xss
bendera. Bendera ini dapat ditentukan baik melalui konfigurasi proyek, atau melalui baris perintah. Format
-Xss
argumennya adalah:
-Xss<size>[g|G|m|M|k|K]