Aplikasi yang gagal jarang diam diam — JVM hampir selalu meninggalkan jejak: stack trace di keluaran, pesan galat saat kelas dimuat, atau proses yang berhenti tanpa keterangan. Masalahnya, jejak itu hanya berguna bagi yang bisa membacanya. Chapter ini melatih dua keterampilan diagnosis yang paling sering dipakai sehari-hari: membedah stack trace baris demi baris, lalu mencocokkan gejala umum — dari OutOfMemoryError hingga deadlock — dengan langkah pemeriksaan pertamanya. Semua alat yang dirujuk di sini bagian dari JDK 25.
Membaca Stack Trace seperti Alamat #
Masalahnya klasik: program berhenti mendadak dan terminal menampilkan belasan baris at yang tampak rumit. Mekanismenya sederhana — ketika exception tidak tertangkap, JVM mencetak tiga bagian ke stderr: nama thread yang mati, jenis exception beserta pesannya, lalu daftar stack frame dari titik pelemparan sampai method main. Program berikut sengaja memuat data yang rusak agar kita dapat membedah jejaknya:
public class BacaUmur {
public static void main(String[] args) {
String baris = "nama=Budi;umur=dualima";
System.out.println("Membaca konfigurasi : " + baris);
String umur = baris.split(";")[1].substring(5);
System.out.println("Nilai umur mentah : " + umur);
// Baris berikut melempar NumberFormatException karena "dualima"
// bukan representasi bilangan yang sah.
int angka = Integer.parseInt(umur);
System.out.println("Umur terbaca : " + angka);
}
}Output yang Dihasilkan (stdout dan stderr tergabung, exit code 1):
Membaca konfigurasi : nama=Budi;umur=dualima
Nilai umur mentah : dualima
Exception in thread "main" java.lang.NumberFormatException: For input string: "dualima"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:565)
at java.base/java.lang.Integer.parseInt(Integer.java:662)
at BacaUmur.main(BacaUmur.java:13)Mari kita bedah jejaknya baris demi baris:
Membaca konfigurasidanNilai umur mentah: dua baris pertama adalah stdout program — nilainya sudah dicetak sebelum kegagalan terjadi. Dari sini kita tahu data masukannya"dualima".Exception in thread "main": thread yang mati adalahmain— karena program kita berjalan single-threaded, seluruh proses berhenti dengan exit code 1.java.lang.NumberFormatException: For input string: "dualima": jenis exception dan pesannya. Akar masalah sudah terbaca di sini —Integer.parseIntmenerima string yang bukan bilangan.- Empat baris
at ...: stack frame dari titik pelemparan ke pemanggil terluar. Frame paling bawah milik kode kita:BacaUmur.maindi baris 13 — baris tepat tempatInteger.parseInt(umur)dipanggil. Frame lain milik JDK dan jarang perlu diselidiki.
Pola pentingnya: frame kode Anda hampir selalu paling bawah, jadi bacalah trace dari bawah ke atas sampai bertemu baris milik proyek sendiri. Perbaikannya pun jelas terarah — bukan pada parseInt, melainkan pada data yang masuk tanpa validasi.
Resep Diagnosis Cepat #
Lima masalah berikut menutup sebagian besar kegagalan runtime yang dijumpai sehari-hari. Tabel ini dirancang untuk dibaca saat insiden: temukan gejalanya, jalankan diagnosis pertamanya:
| Masalah | Gejala khas | Diagnosis pertama |
|---|---|---|
OutOfMemoryError: Java heap space | program melambat lalu mati saat beban naik | aktifkan -XX:+HeapDumpOnOutOfMemoryError, periksa objek terbesar di heap dump |
StackOverflowError | trace panjang berisi method yang sama berulang | cari method berulang di trace, periksa kondisi berhenti rekursinya |
ClassCastException | gagal saat runtime pada cast yang tidak dapat diperiksa compiler | baca pesan X cannot be cast to Y, periksa tipe asli sebelum cast |
ClassNotFoundException vs NoClassDefFoundError | kelas tidak dapat dimuat saat berjalan | yang pertama: nama kelas atau classpath salah; yang kedua: kelas ada saat kompilasi tetapi hilang saat runtime — periksa dependensi |
| Deadlock | aplikasi diam, thread tidak maju, CPU rendah | jcmd <pid> Thread.print — JVM menandai Found one Java-level deadlock beserta kunci yang terlibat |
Bedanya dua galat pemuatan kelas layak ditegaskan karena paling sering tertukar: ClassNotFoundException dilempar kode yang secara eksplisit memuat kelas lewat nama (mis. Class.forName) — salah ketik dan classpath adalah curiga utama; NoClassDefFoundError muncul saat JVM memuat kelas yang sudah dipakai saat kompilasi — biasanya dependensi yang hilang saat runtime, bukan salah ketik.
Alat Bawaan JDK #
Ketiga alat berikut menempel pada proses JVM yang hidup dan tidak memerlukan instalasi tambahan. jcmd <pid> Thread.print mengambil snapshot seluruh thread beserta status kuncinya — alat pertama untuk kecurigaan deadlock dan thread macet. jcmd <pid> GC.heap_info menampilkan ringkasan penggunaan heap per pool. jstack <pid> adalah alat klasik dengan keluaran serupa. Untuk kegagalan yang perlu diselidiki mundur, Java Flight Recorder merekam peristiwa JVM berkelanjutan dengan biaya rendah.
Panduan lengkap tiap skenario dihimpun di Troubleshooting Guide resmi untuk JDK 25; halaman manual tiap tool menjelaskan seluruh subperintahnya. Setelah masalah teratasi, catat resep yang berhasil — halaman berikutnya merangkum istilah Course dalam satu glossary ringkas.
Referensi #
- Oracle: Troubleshooting Guide (JDK 25)
- Oracle: Troubleshoot Memory Leaks (JDK 25)
- Oracle: Manual jcmd (JDK 25)
- Oracle: Manual jstack (JDK 25)
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
BacaUmur.java
Unduh berkaspublic class BacaUmur {
public static void main(String[] args) {
String baris = "nama=Budi;umur=dualima";
System.out.println("Membaca konfigurasi : " + baris);
String umur = baris.split(";")[1].substring(5);
System.out.println("Nilai umur mentah : " + umur);
// Baris berikut melempar NumberFormatException karena "dualima"
// bukan representasi bilangan yang sah.
int angka = Integer.parseInt(umur);
System.out.println("Umur terbaca : " + angka);
}
}