Apakah * pernah * tidak apa-apa untuk menangkap StackOverflowError di Jawa?

27

Dulu saya berpikir itu bukan, tapi kemarin saya harus melakukannya. Ini adalah aplikasi yang menggunakan Akka (implementasi sistem aktor untuk JVM) untuk memproses pekerjaan yang tidak sinkron. Salah satu aktor melakukan beberapa manipulasi PDF, dan karena perpustakaannya bermasalah, ia mati StackOverflowErrorsetiap saat.

Aspek kedua adalah bahwa Akka dikonfigurasi untuk mematikan seluruh sistem aktornya jika ada kesalahan fatal JVM (mis. StackOverflowError) tertangkap.

Aspek ketiga adalah bahwa sistem aktor ini tertanam di dalam aplikasi web (untuk WTF-ish, warisan, alasan), jadi ketika sistem aktor dimatikan, aplikasi web tidak. Efek bersihnya adalah bahwa pada StackOverflowErroraplikasi pemrosesan pekerjaan kita menjadi hanya aplikasi web kosong.

Sebagai perbaikan cepat saya harus menangkap StackOverflowErrorpelemparan, sehingga kumpulan benang dari sistem aktor tidak dirobohkan. Ini membuat saya berpikir bahwa mungkin kadang-kadang tidak apa-apa untuk menangkap kesalahan seperti itu terutama dalam konteks seperti ini? Kapan ada kumpulan thread yang memproses tugas sewenang-wenang? Tidak seperti OutOfMemoryErrorsaya tidak dapat membayangkan bagaimana seorang StackOverflowErrordapat meninggalkan aplikasi dalam keadaan tidak konsisten. Tumpukan dihapus setelah kesalahan seperti itu, sehingga perhitungan dapat berjalan secara normal. Tapi mungkin aku melewatkan sesuatu yang penting.

Juga, perlu dicatat bahwa saya semua untuk memperbaiki kesalahan di tempat pertama (sebenarnya saya sudah memperbaiki BUMN di aplikasi yang sama beberapa hari yang lalu), tapi saya benar-benar tidak tahu kapan ini situasi semacam itu mungkin muncul.

Mengapa lebih baik memulai kembali proses JVM daripada menangkap StackOverflowError, menandai pekerjaan itu gagal, dan melanjutkan bisnis saya?

Apakah ada alasan kuat untuk tidak pernah menangkap BUMN? Kecuali "praktik terbaik", yang merupakan istilah tidak jelas yang tidak memberi tahu saya apa pun.

Ionuț G. Stan
sumber
1
pilihan lain adalah menambah ruang stack yang tersedia di JVM
ratchet freak
3
@ratchetfreak: StackOverflowExceptions biasanya karena rantai panggilan metode yang tidak berhenti - meningkatkan ruang stack kemudian akan meningkatkan biaya memori utas baru tanpa manfaat.
jhominal
1
Setidaknya satu BUMN sah karena inputnya sangat besar. Sayangnya, menanganinya dengan implementasi rekursif (Java's regex impl.) Bukan ide yang sangat bagus. Lagi pula, bahkan ketika perhitungan dijamin akan berakhir, Anda tidak tahu apakah ukuran tumpukan baru cukup besar untuk perhitungan lainnya.
Ionuț G. Stan
2
Bukankah ini harus dimigrasi ke Sta ... Oh, tunggu ... tidak apa-apa. :-)
Blrfl
Mengenai perpustakaan kereta Anda. Anda harus benar-benar memigrasikan fungsi memanipulasi pdf ke dalam prosesnya sendiri sehingga Anda dapat membiarkan os membunuhnya.
Esben Skov Pedersen

Jawaban:

44

Sebagai aturan umum, jika sama sekali tidak pernah dapat diterima untuk melakukan sesuatu, dan ada kesepakatan tentang itu, para pelaksana bahasa tidak akan mengizinkannya. Hampir tidak ada maksim yang jelas seperti itu. (Untungnya, karena itulah yang membuat kami programmer manusia dalam pekerjaan!)

Tampaknya sangat seolah-olah Anda telah menemukan situasi di mana menangkap kesalahan ini adalah pilihan terbaik untuk Anda: itu memungkinkan aplikasi Anda bekerja, sementara semua alternatif lain tidak, dan itulah yang terpenting pada akhirnya. Semua "praktik terbaik" hanyalah ringkasan dari pengalaman panjang dengan banyak kasus yang biasanya dapat digunakan sebagai pengganti analisis rinci dari kasus tertentu untuk menghemat waktu; dalam kasus Anda, Anda sudah melakukan analisis spesifik dan mendapat hasil berbeda. Selamat, Anda mampu berpikir mandiri!

(Yang mengatakan, pasti ada situasi di mana stack overflow mungkin meninggalkan aplikasi tidak konsisten seperti kelelahan memori. Bayangkan saja beberapa objek dibangun dan kemudian diinisialisasi dengan bantuan panggilan metode internal bersarang - jika salah satu dari mereka melempar, objek tersebut mungkin dalam keadaan tidak seharusnya menjadi mungkin, seperti jika alokasi telah gagal. Tapi itu tidak berarti bahwa solusi Anda masih belum menjadi yang terbaik.)

Kilian Foth
sumber
3
Terima kasih. Keraguan saya agak diperkuat setelah saya menemukan bahwa .NET membuat StackOverflowExceptionpengecualian yang tidak bisa ditangkap. Saya tahu, ini platform yang berbeda, tetapi saya pikir mereka mungkin punya alasan. Juga, poin Anda berkaitan dengan inisialisasi objek tepat. Ini membuat saya berpikir bahwa saya harus menangkap SOE ini beberapa lapisan abstraksi di bawah, sehingga saya tidak menangkap SOE yang "salah".
Ionuț G. Stan
14
+1: praktik terbaik harus selalu disertai dengan penjelasan mengapa dan dalam konteks apa mereka "terbaik", sehingga Anda dapat menilai apakah itu berlaku untuk kasus spesifik Anda.
Michael Borgwardt
situations hereseharusnya situations where.
Servy
2

Saya tidak tahu apakah ada risiko spesifik JVM di sini, tetapi secara keseluruhan tampaknya cukup masuk akal.

Sebagai contoh ada algoritma rekursif, seperti quicksort naif, yang memiliki log(n)kedalaman tumpukan dalam kasus khas, tetapi dalam kasus terburuk mereka menurun ke kedalaman nyang dapat meledakkan tumpukan.

Kasus terburuk jarang terjadi, dan tidak mungkin terjadi lagi jika Anda me-restart mengurutkan pada set yang diurutkan sebagian, sehingga masuk akal untuk menangkap pengecualian stack overflow ketika itu terjadi dan memulai kembali pekerjaan alih-alih mencoba mencegah kesalahan terjadi atau membunuh seluruh aplikasi.

Kornel
sumber