Mencari Kebocoran Memori Di Program Java Dengan JVisualVM dan Eclipse MemoryAnalyzer


Kebocoran memori pada sebuah program terjadi bila programmer memakai memori untuk menampung data tetapi tidak melepaskan wilayah memori tersebut walaupun data sudah tidak dipakai lagi. Bila hal ini terjadi terus menerus, sebanyak apapun memori yang tersedia, pada akhirnya akan ‘habis’. Istilah ‘habis’ yang dimaksud adalah data di memori secara logika sesungguhnya sudah tidak dipakai lagi dan boleh digunakan untuk menampung data baru, tetapi yang terjadi adalah wilayah memori tersebut tetap dianggap sedang dipakai.

Pada bahasa C, pengguna dapat meminta wilayah memori untuk dipakai dengan menggunakan malloc(). Setelah tidak dibutuhkan lagi, wilayah memori tersebut dilepaskan dengan menggunakan free(). Pada Java, programmer perlu mengalokasikan penggunaan memori dengan new tetapi tidak perlu melepaskan wilayah memori tersebut secara manual. Fasilitas garbage collector di Java akan mencari object yang sudah tidak pakai dan mem-‘buang’-nya secara otomatis. Garbage collector selalu bekerja di balik layar pada saat program Java dijalankan.

Bila sudah ada garbage collector, apakah itu berarti kebocoran memori tidak akan terjadi di program yang dibuat dengan Java? Tidak juga! Garbage collector hanya akan mem-‘buang’ object yang benar-benar tidak dirujuk oleh object lainnya lagi. Jadi, walaupun sebuah object sudah tidak dipakai lagi, tetapi bila masih ada object lain yang menyimpan referensinya, maka garbage collector tidak akan mem-‘buang’ object tersebut.

Sebagai contoh, saya memantau sebuah program Java yang saya buat dengan menggunakan JVisualVM. Ini adalah tool bawaan JDK yang dapat dijumpai di folder seperti C:\Program Files\java\jdk1.7\bin\jvisualvm.exe. Sebagai informasi, di folder ini juga masih ada banyak tool berguna lainnya yang tidak memiliki shortcut di Start Menu. Setelah menjalankan JVisualVM, saya dapat melihat semua program Java yang sedang berjalan di komputer lokal di window Applications . Saya kemudian men-double click pada program Java yang hendak saya pantau. Setelah itu, saya men-klik pada tab Monitor. Pada bagian Heap, saya menemukan tampilan seperti pada gambar berikut ini:

Grafik menunjukkan ada kebocoran memori

Grafik menunjukkan ada kebocoran memori

Grafik di atas memperlihatkan memori di heap secara terus menerus meningkat hingga mencapai batas maksimal yang diperbolehkan. Ini akan menyebabkan program Java berjalan sangat lambat. Bahkan setelah saya men-klik tombol Perform GC, grafik tidak menunjukkan penurunan wilayah heap yang terpakai. Saya yakin telah terjadi kebocoran memori yang sangat besar karena program saya saat ini tidak sedang melakukan apa-apa. Bagaimana mungkin sebuah program yang sedang santai ‘memakan’ memori sebesar itu?

Lalu bagaimana cara mengetahui kode program mana yang menyebabkan terjadinya kebocoran memori? Saya akan mulai melakukan troubleshooting dengan men-klik tombol Heap Dump. Pada window Applications, saya men-klik kanan heap dump yang dihasilkan dan memilih Save As untuk menyimpannya sebagai sebuah file.

Saya akan menggunakan Eclipse MemoryAnalyzer (MAT) untuk melakukan analisa secara otomatis. MAT dapat di-download sebagai sebuah aplikasi standalone (Eclipse RCP) di http://eclipse.org/mat/downloads.php. Setelah men-extract file zip yang di-download, saya men-double click file MemoryAnalyzer.exe untuk menjalankan MAT. Setelah program dijalankan, saya memilih menu File, Open Heap Dump… untuk membuka file heap dump yang sudah saya buat sebelumnya. Pada dialog Getting Started, saya memilih Leak Suspects Report dan men-klik tombol Finish.

Setelah proses analisa selesai, saya memperoleh laporan seperti yang terlihat pada gambar berikut ini:

Hasil analisa Eclipse MemoryAnalyzer

Hasil analisa Eclipse MemoryAnalyzer

Laporan tersebut memperlihatkan bahwa ada 31 object yang merupakan instance dari class PrintPreviewPane yang memakai hingga 67% memori di heap. Padahal seluruh JPanel tersebut sudah tidak dipakai lagi karena saya sudah menutup dialog-nya sejak lama. Saya sudah menemukan ‘tersangka’! Langkah selanjutnya adalah mengetahui kronologi kejadian agar saya bisa memperbaiki kebocoran ini. Untuk itu, saya bisa melihat pada bagian Reference Pattern seperti pada gambar berikut ini:

Output pada Reference pattern

Output pada Reference pattern

Ternyata PrintPreviewPane adalah sebuah JPanel yang ditampilkan melalui JDialog. Bila seandainya setiap JDialog yang ada tersebut dibersihkan oleh garbage collector, program bisa memperoleh memori sebesar 144 MB untuk dipakai ulang. Seluruh child dan data yang terkandung di dalam PrintPreviewPane tidak dihapus sama sekali oleh garbage collector.

Mengapa garbage collector tidak membuang JDialog yang sudah tidak ditampilkan dari memori? Ini adalah kesalahan klasik dimana saya lupa memanggil dispose() dari JDialog setelah menutup dialog tersebut. Pada Swing, hampir seluruh top-level container seperti JFrame, JDialog, JWindow dan sebagainya harus di-dispose() bila sudah tidak dipakai lagi. Loh, bukankah seharusnya garbage collector bekerja secara pintar? Masalahnya, top-level container memakai resource spesifik milik sistem operasi yang berhubungan dengan GUI. Selain itu, top-level container juga bisa ditampilkan ulang setelah ditutup, misalnya dengan setVisible(true). Hanya dengan dispose() baru seluruh alokasi sumber daya milik sistem operasi tersebut akan benar-benar dilepaskan.

Saya pun segera memperbaiki kesalahan pada kode program Java yang saya buat, misalnya dengan menambahkan kode program seperti:

d.dispose();
d = null;

Sekarang, bila saya memakai JVisualVM untuk memantau aktifitas memori, saya akan menemukan hasil seperti pada gambar berikut ini:

Aktifitas memori setelah kebocoran 'besar' diperbaiki

Aktifitas memori setelah kebocoran ‘besar’ diperbaiki

Terlihat bahwa garbage collector berhasil menghapus object yang tidak dibutuhkan dimana grafik penggunaan memori terlihat menurun. Kebocoran memori mungkin saja masih terjadi, tetapi tidak ada lagi kebocoran ‘besar’ yang menyebabkan program menjadi sangat lambat akibat kehabisan memori.

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: