Saya telah memiliki contoh kode Java kami menangkap NullPointerException
, tetapi ketika saya mencoba untuk log StackTrace (yang pada dasarnya berakhir memanggil Throwable.printStackTrace()
), yang saya dapatkan adalah:
java.lang.NullPointerException
Adakah yang menemukan ini? Saya mencoba googling untuk "java null pointer empty stack trace" tetapi tidak menemukan yang seperti ini.
java
nullpointerexception
Edward Shtern
sumber
sumber
-XX:-OmitStackTraceInFastThrow
di dup: stackoverflow.com/questions/4659151/…Jawaban:
Anda mungkin menggunakan JVM HotSpot (awalnya oleh Sun Microsystems, kemudian dibeli oleh Oracle, bagian dari OpenJDK), yang melakukan banyak optimasi. Untuk mendapatkan jejak stack kembali, Anda harus meneruskan opsi
-XX:-OmitStackTraceInFastThrow
ke JVM.Optimalisasi adalah ketika pengecualian (biasanya NullPointerException) terjadi untuk pertama kalinya, jejak tumpukan penuh dicetak dan JVM mengingat jejak tumpukan (atau mungkin hanya lokasi kode). Ketika pengecualian itu terjadi cukup sering, jejak tumpukan tidak dicetak lagi, baik untuk mencapai kinerja yang lebih baik dan tidak membanjiri log dengan jejak tumpukan yang identik.
Untuk melihat bagaimana ini diterapkan di HotSpot JVM, ambil salinannya dan cari variabel global
OmitStackTraceInFastThrow
. Terakhir kali saya melihat kode (pada 2019), itu ada di file graphKit.cpp .sumber
-XX:-OmitStackTraceInFastThrow
flag juga. Saya belum mengkonfirmasi apakah itu sebabnya saya juga gagal mencetak tumpukan-jejak (misalnya, menggunakane.printStackTrace
), tetapi tampaknya sangat mungkin. Saya telah memperluas jawaban untuk mencerminkan penemuan ini.Seperti yang Anda sebutkan dalam komentar, Anda menggunakan log4j. Saya menemukan (secara tidak sengaja) tempat di mana saya telah menulis
bukannya tipikal
melalui kemalasan atau mungkin hanya tidak memikirkannya. Bagian yang disayangkan dari ini adalah bahwa itu tidak berperilaku seperti yang Anda harapkan. API logger sebenarnya mengambil Object sebagai argumen pertama, bukan string - dan kemudian memanggil toString () pada argumen. Jadi alih-alih mendapatkan jejak tumpukan yang bagus, itu hanya mencetak toString - yang dalam kasus NPE sangat tidak berguna.
Mungkin ini yang Anda alami?
sumber
Kami telah melihat perilaku yang sama di masa lalu. Ternyata, untuk beberapa alasan gila, jika NullPointerException terjadi di tempat yang sama dalam kode beberapa kali, setelah beberapa saat menggunakan
Log.error(String, Throwable)
akan berhenti termasuk jejak tumpukan penuh.Coba cari lebih jauh ke belakang di log Anda. Anda mungkin menemukan pelakunya.
EDIT: bug ini kedengarannya relevan, tetapi sudah diperbaiki sejak lama mungkin itu bukan penyebabnya.
sumber
-XX:-OmitStackTraceInFastThrow
bendera JVM yang disarankan oleh Joshua? Lihat juga stackoverflow.com/a/2070568/6198 .Berikut ini penjelasannya: Hotspot menyebabkan pengecualian untuk kehilangan jejak tumpukan mereka dalam produksi - dan perbaikannya
Saya sudah mengujinya di Mac OS X
Java HotSpot (TM) 64-Bit Server VM (build 20.1-b02-383, mode campuran)
Untuk fragmen kode khusus ini, 12288 iterasi (frekuensi +?) Tampaknya menjadi batas di mana JVM telah memutuskan untuk menggunakan pengecualian yang telah dialokasikan sebelumnya ...
sumber
exception.toString
tidak memberi Anda StackTrace, itu hanya mengembalikanGunakan
exception.printStackTrace
sebaliknya untuk menampilkan StackTrace.sumber
getStackTrace()
untuk memastikan masalahnya bukan pada logger Anda?Saran alternatif - jika Anda menggunakan Eclipse, Anda bisa menetapkan breakpoint pada NullPointerException itu sendiri (dalam perspektif Debug, buka tab "Breakpoints" dan klik pada ikon kecil yang memiliki! Di dalamnya)
Periksa opsi "tertangkap" dan "tidak tertangkap" - sekarang ketika Anda memicu NPE, Anda akan segera menerobos dan Anda kemudian dapat melangkah dan melihat bagaimana tepatnya ditangani dan mengapa Anda tidak mendapatkan jejak tumpukan.
sumber
toString()
hanya mengembalikan nama pengecualian dan pesan opsional. Saya sarankan meneleponuntuk membuang pesan, atau jika Anda memerlukan detail berdarah:
sumber
(Pertanyaan Anda masih belum jelas tentang apakah kode Anda memanggil
printStackTrace()
atau ini sedang dilakukan oleh penangan log.)Berikut adalah beberapa penjelasan yang mungkin tentang apa yang mungkin terjadi:
Logger / handler yang digunakan telah dikonfigurasi untuk hanya menampilkan string pesan pengecualian, bukan jejak stack penuh.
Aplikasi Anda (atau pustaka pihak ketiga) sedang mencatat pengecualian menggunakan
LOG.error(ex);
daripada bentuk 2-argumen dari (misalnya) metode log4j Logger.Pesan tersebut datang dari tempat yang berbeda dari tempat Anda pikir; misalnya itu sebenarnya datang beberapa metode perpustakaan pihak ketiga, atau beberapa hal acak yang tersisa dari upaya sebelumnya untuk debug.
Pengecualian yang sedang dicatat telah membebani beberapa metode untuk mengaburkan stacktrace. Jika demikian, pengecualian tidak akan menjadi NullPointerException asli, tetapi akan menjadi subtipe khusus NPE atau bahkan beberapa pengecualian yang tidak terhubung.
Saya pikir penjelasan terakhir yang mungkin sangat tidak mungkin, tetapi orang setidaknya berpikir untuk melakukan hal semacam ini untuk "mencegah" rekayasa terbalik. Tentu saja itu hanya berhasil membuat hidup menjadi sulit bagi pengembang yang jujur.
sumber
Saat Anda menggunakan AspectJ dalam proyek Anda, mungkin saja beberapa aspek menyembunyikan bagiannya dari jejak tumpukan. Misalnya, hari ini saya punya:
Jejak tumpukan ini dicetak saat menjalankan tes melalui Maven's surefire.
Di sisi lain, ketika menjalankan tes di IntelliJ, jejak tumpukan yang berbeda dicetak:
sumber
Ini akan menghasilkan Pengecualian, gunakan hanya untuk debug Anda harus menangani pengecualian Anda lebih baik.
sumber