Berburu Kebocoran Memori Java

Diterbitkan: 2022-03-11

Pemrogram yang tidak berpengalaman sering berpikir bahwa pengumpulan sampah otomatis Java benar-benar membebaskan mereka dari kekhawatiran tentang manajemen memori. Ini adalah kesalahan persepsi yang umum: sementara pengumpul sampah melakukan yang terbaik, sangat mungkin bagi programmer terbaik untuk menjadi mangsa kebocoran memori yang melumpuhkan. Mari saya jelaskan.

Kebocoran memori terjadi ketika referensi objek yang tidak lagi diperlukan dipertahankan secara tidak perlu. Kebocoran ini buruk. Pertama, mereka memberikan tekanan yang tidak perlu pada mesin Anda karena program Anda menghabiskan lebih banyak sumber daya. Lebih buruk lagi, mendeteksi kebocoran ini bisa jadi sulit: analisis statis sering kali kesulitan untuk mengidentifikasi referensi yang berlebihan ini secara tepat, dan alat pendeteksi kebocoran yang ada melacak dan melaporkan informasi terperinci tentang objek individual, menghasilkan hasil yang sulit ditafsirkan dan kurang presisi.

Dengan kata lain, kebocoran terlalu sulit untuk diidentifikasi, atau diidentifikasi dalam istilah yang terlalu spesifik untuk berguna.

Sebenarnya ada empat kategori masalah memori dengan gejala yang serupa dan tumpang tindih, tetapi penyebab dan solusinya bervariasi:

  • Kinerja : biasanya terkait dengan pembuatan dan penghapusan objek yang berlebihan, penundaan yang lama dalam pengumpulan sampah, pertukaran halaman sistem operasi yang berlebihan, dan banyak lagi.

  • Kendala sumber daya : terjadi ketika memori yang tersedia hanya sedikit atau memori Anda terlalu terfragmentasi untuk mengalokasikan objek yang besar—ini bisa asli atau, lebih umum, terkait heap Java.

  • Kebocoran heap Java : kebocoran memori klasik, di mana objek Java terus dibuat tanpa dirilis. Ini biasanya disebabkan oleh referensi objek laten.

  • Kebocoran memori asli : terkait dengan pemanfaatan memori yang terus berkembang yang berada di luar heap Java, seperti alokasi yang dibuat oleh kode JNI, driver, atau bahkan alokasi JVM.

Dalam tutorial manajemen memori ini, saya akan fokus pada kebocoran tumpukan Java dan menguraikan pendekatan untuk mendeteksi kebocoran tersebut berdasarkan laporan Java VisualVM dan memanfaatkan antarmuka visual untuk menganalisis aplikasi berbasis teknologi Java saat sedang berjalan.

Tetapi sebelum Anda dapat mencegah dan menemukan kebocoran memori, Anda harus memahami bagaimana dan mengapa hal itu terjadi. ( Catatan: Jika Anda memiliki pegangan yang baik pada seluk-beluk kebocoran memori, Anda dapat melompat ke depan. )

Kebocoran Memori: Sebuah Primer

Sebagai permulaan, anggap kebocoran memori sebagai penyakit dan Java's OutOfMemoryError (OOM, untuk singkatnya) sebagai gejala. Tetapi seperti halnya penyakit apa pun, tidak semua OOM menyiratkan kebocoran memori : OOM dapat terjadi karena pembangkitan sejumlah besar variabel lokal atau peristiwa serupa lainnya. Di sisi lain, tidak semua kebocoran memori dengan sendirinya bermanifestasi sebagai OOMs , terutama dalam kasus aplikasi desktop atau aplikasi klien (yang tidak berjalan lama tanpa restart).

Pikirkan kebocoran memori sebagai penyakit dan OutOfMemoryError sebagai gejala. Tetapi tidak semua OutOfMemoryErrors menyiratkan kebocoran memori, dan tidak semua kebocoran memori memanifestasikan dirinya sebagai OutOfMemoryErrors.

Mengapa kebocoran ini sangat buruk? Antara lain, blok memori yang bocor selama eksekusi program sering menurunkan kinerja sistem dari waktu ke waktu, karena blok memori yang dialokasikan tetapi tidak digunakan harus ditukar setelah sistem kehabisan memori fisik yang kosong. Akhirnya, sebuah program bahkan dapat menghabiskan ruang alamat virtual yang tersedia, yang mengarah ke OOM.

Menguraikan OutOfMemoryError

Seperti disebutkan di atas, OOM adalah indikasi umum kebocoran memori. Pada dasarnya, kesalahan terjadi ketika tidak ada cukup ruang untuk mengalokasikan objek baru. Berusaha sekuat tenaga, pengumpul sampah tidak dapat menemukan ruang yang diperlukan, dan tumpukan tidak dapat diperluas lebih jauh. Dengan demikian, kesalahan muncul, bersama dengan jejak tumpukan.

Langkah pertama dalam mendiagnosis OOM Anda adalah menentukan apa arti sebenarnya dari kesalahan tersebut. Ini terdengar jelas, tetapi jawabannya tidak selalu begitu jelas. Misalnya: Apakah OOM muncul karena tumpukan Java penuh, atau karena tumpukan asli penuh? Untuk membantu Anda menjawab pertanyaan ini, mari kita menganalisis beberapa kemungkinan pesan kesalahan:

  • java.lang.OutOfMemoryError: Java heap space

  • java.lang.OutOfMemoryError: PermGen space

  • java.lang.OutOfMemoryError: Requested array size exceeds VM limit

  • java.lang.OutOfMemoryError: request <size> bytes for <reason>. Out of swap space?

  • java.lang.OutOfMemoryError: <reason> <stack trace> (Native method)

“Ruang tumpukan Java”

Pesan kesalahan ini tidak selalu menyiratkan kebocoran memori. Faktanya, masalahnya bisa sesederhana masalah konfigurasi.

Misalnya, saya bertanggung jawab untuk menganalisis aplikasi yang secara konsisten menghasilkan jenis OutOfMemoryError ini. Setelah beberapa penyelidikan, saya menemukan bahwa pelakunya adalah instantiasi array yang menuntut terlalu banyak memori; dalam hal ini, itu bukan kesalahan aplikasi, melainkan, server aplikasi mengandalkan ukuran heap default, yang terlalu kecil. Saya memecahkan masalah dengan menyesuaikan parameter memori JVM.

Dalam kasus lain, dan khususnya untuk aplikasi yang berumur panjang, pesan tersebut mungkin merupakan indikasi bahwa kita secara tidak sengaja menyimpan referensi ke objek , mencegah pengumpul sampah membersihkannya. Ini adalah bahasa Java yang setara dengan kebocoran memori . ( Catatan: API yang dipanggil oleh aplikasi juga bisa secara tidak sengaja menyimpan referensi objek. )

Sumber potensial lain dari OOM “Java heap space” ini muncul dengan penggunaan finalizer . Jika sebuah kelas memiliki metode finalize , maka objek dari tipe tersebut tidak memiliki ruang yang direklamasi pada waktu pengumpulan sampah. Sebagai gantinya, setelah pengumpulan sampah, objek diantrekan untuk finalisasi, yang terjadi kemudian. Dalam implementasi Sun, finalizer dieksekusi oleh daemon thread. Jika utas finalizer tidak dapat mengikuti antrian finalisasi, maka tumpukan Java dapat terisi dan OOM dapat dilempar.

“Ruang PermGen”

Pesan kesalahan ini menunjukkan bahwa generasi permanen sudah penuh. Generasi permanen adalah area heap yang menyimpan objek kelas dan metode. Jika aplikasi memuat sejumlah besar kelas, maka ukuran generasi permanen mungkin perlu ditingkatkan menggunakan opsi -XX:MaxPermSize .

Objek java.lang.String yang diinternir juga disimpan dalam generasi permanen. Kelas java.lang.String memelihara kumpulan string. Saat metode intern dipanggil, metode tersebut memeriksa kumpulan untuk melihat apakah ada string yang setara. Jika demikian, itu dikembalikan dengan metode magang; jika tidak, string ditambahkan ke pool. Dalam istilah yang lebih tepat, metode java.lang.String.intern mengembalikan representasi kanonik string; hasilnya adalah referensi ke instance kelas yang sama yang akan dikembalikan jika string itu muncul sebagai literal. Jika aplikasi menginternalisasi string dalam jumlah besar, Anda mungkin perlu menambah ukuran generasi permanen.

Catatan: Anda dapat menggunakan perintah jmap -permgen untuk mencetak statistik yang terkait dengan pembuatan permanen, termasuk informasi tentang instance String yang diinternalisasi.

“Ukuran array yang diminta melebihi batas VM”

Kesalahan ini menunjukkan bahwa aplikasi (atau API yang digunakan oleh aplikasi itu) berusaha mengalokasikan larik yang lebih besar dari ukuran tumpukan. Misalnya, jika aplikasi mencoba mengalokasikan array 512MB tetapi ukuran heap maksimum 256MB, maka OOM akan ditampilkan dengan pesan kesalahan ini. Dalam kebanyakan kasus, masalahnya adalah masalah konfigurasi atau bug yang terjadi saat aplikasi mencoba mengalokasikan array besar.

“Minta byte <size> untuk <alasan>. Kehabisan ruang swap?”

Pesan ini tampaknya merupakan OOM. Namun, VM HotSpot mengeluarkan pengecualian yang nyata ini ketika alokasi dari heap asli gagal dan heap asli mungkin hampir habis. Termasuk dalam pesan adalah ukuran (dalam byte) permintaan yang gagal dan alasan permintaan memori. Dalam kebanyakan kasus, <reason> adalah nama modul sumber yang melaporkan kegagalan alokasi.

Jika jenis OOM ini muncul, Anda mungkin perlu menggunakan utilitas pemecahan masalah pada sistem operasi Anda untuk mendiagnosis masalah lebih lanjut. Dalam beberapa kasus, masalahnya mungkin tidak terkait dengan aplikasi. Misalnya, Anda mungkin melihat kesalahan ini jika:

  • Sistem operasi dikonfigurasi dengan ruang swap yang tidak mencukupi.

  • Proses lain pada sistem menghabiskan semua sumber daya memori yang tersedia.

Mungkin juga aplikasi gagal karena kebocoran asli (misalnya, jika beberapa kode aplikasi atau pustaka terus mengalokasikan memori tetapi gagal melepaskannya ke sistem operasi).

<reason> <stack trace> (Metode asli)

Jika Anda melihat pesan kesalahan ini dan bingkai teratas pelacakan tumpukan Anda adalah metode asli, maka metode asli tersebut mengalami kegagalan alokasi. Perbedaan antara pesan ini dan sebelumnya adalah bahwa kegagalan alokasi memori Java terdeteksi dalam JNI atau metode asli, bukan dalam kode Java VM.

Jika jenis OOM ini muncul, Anda mungkin perlu menggunakan utilitas pada sistem operasi untuk mendiagnosis masalah lebih lanjut.

Aplikasi Crash Tanpa OOM

Terkadang, aplikasi mungkin mogok segera setelah kegagalan alokasi dari tumpukan asli. Ini terjadi jika Anda menjalankan kode asli yang tidak memeriksa kesalahan yang dikembalikan oleh fungsi alokasi memori.

Misalnya, panggilan sistem malloc mengembalikan NULL jika tidak ada memori yang tersedia. Jika pengembalian dari malloc tidak dicentang, maka aplikasi mungkin macet saat mencoba mengakses lokasi memori yang tidak valid. Tergantung pada situasinya, jenis masalah ini mungkin sulit ditemukan.

Dalam beberapa kasus, informasi dari log kesalahan fatal atau crash dump akan cukup. Jika penyebab crash ditentukan karena kurangnya penanganan kesalahan di beberapa alokasi memori, maka Anda harus mencari alasan kegagalan alokasi tersebut. Seperti halnya masalah tumpukan asli lainnya, sistem mungkin dikonfigurasi dengan ruang swap yang tidak mencukupi, proses lain mungkin menggunakan semua sumber daya memori yang tersedia, dll.

Mendiagnosis Kebocoran

Dalam kebanyakan kasus, mendiagnosis kebocoran memori membutuhkan pengetahuan yang sangat rinci tentang aplikasi yang bersangkutan. Peringatan: prosesnya bisa panjang dan berulang.

Strategi kami untuk memburu kebocoran memori akan relatif mudah:

  1. Identifikasi gejala

  2. Aktifkan pengumpulan sampah verbose

  3. Aktifkan pembuatan profil

  4. Analisis jejaknya

1. Identifikasi Gejala

Seperti yang telah dibahas, dalam banyak kasus, proses Java pada akhirnya akan mengeluarkan pengecualian runtime OOM, indikator yang jelas bahwa sumber daya memori Anda telah habis. Dalam hal ini, Anda perlu membedakan antara kelelahan memori normal dan kebocoran. Menganalisis pesan OOM dan mencoba menemukan pelakunya berdasarkan diskusi yang diberikan di atas.

Seringkali, jika aplikasi Java meminta lebih banyak penyimpanan daripada yang ditawarkan oleh runtime heap, itu bisa disebabkan oleh desain yang buruk. Misalnya, jika aplikasi membuat banyak salinan gambar atau memuat file ke dalam larik, itu akan kehabisan penyimpanan saat gambar atau file sangat besar. Ini adalah kelelahan sumber daya yang normal. Aplikasi ini bekerja seperti yang dirancang (walaupun desain ini jelas-jelas bodoh).

Tetapi jika aplikasi terus meningkatkan pemanfaatan memorinya saat memproses jenis data yang sama, Anda mungkin mengalami kebocoran memori.

2. Aktifkan Pengumpulan Sampah Verbose

Salah satu cara tercepat untuk menegaskan bahwa Anda memang memiliki kebocoran memori adalah dengan mengaktifkan pengumpulan sampah verbose. Masalah kendala memori biasanya dapat diidentifikasi dengan memeriksa pola dalam keluaran verbosegc .

Secara khusus, argumen -verbosegc memungkinkan Anda menghasilkan jejak setiap kali proses pengumpulan sampah (GC) dimulai. Artinya, saat memori sedang dikumpulkan, laporan ringkasan dicetak ke kesalahan standar, memberi Anda gambaran tentang bagaimana memori Anda dikelola.

Berikut ini beberapa keluaran khas yang dihasilkan dengan opsi –verbosegc :

keluaran pengumpulan sampah verbose

Setiap blok (atau bait) dalam file jejak GC ini diberi nomor dalam urutan yang meningkat. Untuk memahami jejak ini, Anda harus melihat bait Kegagalan Alokasi berturut-turut dan mencari memori yang dibebaskan (byte dan persentase) menurun seiring waktu sementara total memori (di sini, 19725304) meningkat. Ini adalah tanda-tanda khas dari penipisan memori.

3. Aktifkan Pembuatan Profil

JVM yang berbeda menawarkan cara berbeda untuk menghasilkan file pelacakan untuk mencerminkan aktivitas heap, yang biasanya menyertakan informasi mendetail tentang jenis dan ukuran objek. Ini disebut membuat profil heap .

4. Analisis Jejak

Posting ini berfokus pada jejak yang dihasilkan oleh Java VisualVM. Jejak dapat datang dalam format yang berbeda, karena dapat dihasilkan oleh alat pendeteksi kebocoran memori Java yang berbeda, tetapi ide di baliknya selalu sama: temukan blok objek di heap yang seharusnya tidak ada di sana, dan tentukan apakah objek ini terakumulasi bukannya melepaskan. Yang menarik adalah objek sementara yang diketahui dialokasikan setiap kali peristiwa tertentu dipicu dalam aplikasi Java. Kehadiran banyak instance objek yang seharusnya hanya ada dalam jumlah kecil umumnya menunjukkan bug aplikasi.

Terakhir, memecahkan kebocoran memori mengharuskan Anda untuk meninjau kode Anda secara menyeluruh. Mempelajari jenis objek yang bocor bisa sangat membantu dan mempercepat proses debug.

Bagaimana Cara Kerja Pengumpulan Sampah di JVM?

Sebelum kita memulai analisis aplikasi dengan masalah kebocoran memori, pertama-tama mari kita lihat cara kerja pengumpulan sampah di JVM.

JVM menggunakan bentuk pengumpul sampah yang disebut tracing collector , yang pada dasarnya beroperasi dengan menjeda dunia di sekitarnya, menandai semua objek root (objek yang direferensikan secara langsung dengan menjalankan utas), dan mengikuti referensinya, menandai setiap objek yang dilihatnya di sepanjang jalan.

Java mengimplementasikan sesuatu yang disebut sebagai pengumpul sampah generasi berdasarkan asumsi hipotesis generasi, yang menyatakan bahwa sebagian besar objek yang dibuat dengan cepat dibuang , dan objek yang tidak dikumpulkan dengan cepat kemungkinan akan ada untuk sementara waktu .

Berdasarkan asumsi ini, Java mempartisi objek menjadi beberapa generasi. Berikut interpretasi visualnya:

Partisi Java menjadi beberapa generasi

  • Generasi Muda - Di sinilah objek dimulai. Ini memiliki dua sub-generasi:

    • Eden Space - Objek dimulai di sini. Sebagian besar objek diciptakan dan dihancurkan di Ruang Eden. Di sini, GC melakukan Minor GCs , yang merupakan pengumpulan sampah yang dioptimalkan. Ketika GC Minor dilakukan, referensi apa pun ke objek yang masih diperlukan dimigrasikan ke salah satu ruang yang selamat (S0 atau S1).

    • Survivor Space (S0 dan S1) - Objek yang bertahan di Eden berakhir di sini. Ada dua di antaranya, dan hanya satu yang digunakan pada waktu tertentu (kecuali jika kita mengalami kebocoran memori yang serius). Satu ditetapkan sebagai kosong , dan yang lainnya sebagai hidup , bergantian dengan setiap siklus GC.

  • Generasi Bertahan - Juga dikenal sebagai generasi lama (ruang lama pada Gambar 2), ruang ini menampung objek yang lebih tua dengan masa pakai yang lebih lama (dipindahkan dari ruang selamat, jika mereka hidup cukup lama). Ketika ruang ini terisi, GC melakukan GC Penuh , yang lebih mahal dalam hal kinerja. Jika ruang ini tumbuh tanpa batas, JVM akan membuang OutOfMemoryError - Java heap space .

  • Generasi Permanen - Generasi ketiga terkait erat dengan generasi bertenor, generasi permanen khusus karena menyimpan data yang dibutuhkan oleh mesin virtual untuk menggambarkan objek yang tidak memiliki kesetaraan di tingkat bahasa Java. Misalnya, objek yang menjelaskan kelas dan metode disimpan dalam generasi permanen.

Java cukup pintar untuk menerapkan metode pengumpulan sampah yang berbeda untuk setiap generasi. Generasi muda ditangani dengan menggunakan tracing, copying collector yang disebut Parallel New Collector . Kolektor ini menghentikan dunia, tetapi karena generasi muda umumnya kecil, jedanya pendek.

Untuk informasi lebih lanjut tentang generasi JVM dan cara kerjanya secara lebih rinci, kunjungi Manajemen Memori di dokumentasi Java HotSpot Virtual Machine.

Mendeteksi Kebocoran Memori

Untuk menemukan kebocoran memori dan menghilangkannya, Anda memerlukan alat kebocoran memori yang tepat. Saatnya untuk mendeteksi dan menghapus kebocoran seperti itu menggunakan Java VisualVM.

Membuat Profil Heap dari Jarak Jauh dengan Java VisualVM

VisualVM adalah alat yang menyediakan antarmuka visual untuk melihat informasi rinci tentang aplikasi berbasis teknologi Java saat sedang berjalan.

Dengan VisualVM, Anda dapat melihat data yang terkait dengan aplikasi lokal dan yang berjalan di host jarak jauh. Anda juga dapat mengambil data tentang instance perangkat lunak JVM dan menyimpan data ke sistem lokal Anda.

Untuk memanfaatkan semua fitur Java VisualVM, Anda harus menjalankan Platform Java, Edisi Standar (Java SE) versi 6 atau lebih tinggi.

Terkait: Mengapa Anda Perlu Meng-upgrade ke Java 8?

Mengaktifkan Koneksi Jarak Jauh untuk JVM

Dalam lingkungan produksi, seringkali sulit untuk mengakses mesin yang sebenarnya di mana kode kita akan dijalankan. Untungnya, kami dapat membuat profil aplikasi Java kami dari jarak jauh.

Pertama, kita perlu memberi diri kita akses JVM pada mesin target. Untuk melakukannya, buat file bernama jstatd.all.policy dengan konten berikut:

 grant codebase "file:${java.home}/../lib/tools.jar" { permission java.security.AllPermission; };

Setelah file dibuat, kita perlu mengaktifkan koneksi jarak jauh ke VM target menggunakan alat jstatd - Mesin Virtual jstat Daemon, sebagai berikut:

 jstatd -p <PORT_NUMBER> -J-Djava.security.policy=<PATH_TO_POLICY_FILE>

Sebagai contoh:

 jstatd -p 1234 -J-Djava.security.policy=D:\jstatd.all.policy

Dengan jstatd yang dimulai di VM target, kami dapat terhubung ke mesin target dan membuat profil aplikasi dari jarak jauh dengan masalah kebocoran memori.

Menghubungkan ke Host Jarak Jauh

Di mesin klien, buka prompt dan ketik jvisualvm untuk membuka alat VisualVM.

Selanjutnya, kita harus menambahkan remote host di VisualVM. Karena JVM target diaktifkan untuk mengizinkan koneksi jarak jauh dari komputer lain dengan J2SE 6 atau lebih tinggi, kami memulai alat Java VisualVM dan terhubung ke host jarak jauh. Jika koneksi dengan remote host berhasil, kita akan melihat aplikasi Java yang berjalan di JVM target, seperti yang terlihat di sini:

berjalan di target jvm

Untuk menjalankan profiler memori pada aplikasi, kita cukup mengklik dua kali namanya di panel samping.

Sekarang setelah kita siap dengan penganalisis memori, mari kita selidiki aplikasi dengan masalah kebocoran memori, yang akan kita sebut MemLeak .

MemLeak

Tentu saja, ada beberapa cara untuk membuat kebocoran memori di Java. Untuk kesederhanaan, kami akan mendefinisikan kelas sebagai kunci dalam HashMap , tetapi kami tidak akan mendefinisikan metode equals() dan hashcode() .

HashMap adalah implementasi tabel hash untuk antarmuka Peta, dan karena itu mendefinisikan konsep dasar kunci dan nilai: setiap nilai terkait dengan kunci unik, jadi jika kunci untuk pasangan nilai kunci yang diberikan sudah ada di HashMap, nilainya saat ini diganti.

Kelas kunci kita wajib menyediakan implementasi yang benar dari metode equals() dan hashcode() . Tanpa mereka, tidak ada jaminan bahwa kunci yang baik akan dihasilkan.

Dengan tidak mendefinisikan metode equals() dan hashcode() , kami menambahkan kunci yang sama ke HashMap berulang kali dan, alih-alih mengganti kunci sebagaimana mestinya, HashMap terus tumbuh, gagal mengidentifikasi kunci identik ini dan melemparkan OutOfMemoryError .

Inilah kelas MemLeak:

 package com.post.memory.leak; import java.util.Map; public class MemLeak { public final String key; public MemLeak(String key) { this.key =key; } public static void main(String args[]) { try { Map map = System.getProperties(); for(;;) { map.put(new MemLeak("key"), "value"); } } catch(Exception e) { e.printStackTrace(); } } }

Catatan: kebocoran memori bukan karena infinite loop pada baris 14: infinite loop dapat menyebabkan kehabisan sumber daya, tetapi bukan kebocoran memori. Jika kita telah menerapkan metode equals() dan hashcode() dengan benar, kode akan berjalan dengan baik bahkan dengan infinite loop karena kita hanya akan memiliki satu elemen di dalam HashMap.

(Bagi mereka yang tertarik, berikut adalah beberapa cara alternatif (dengan sengaja) menghasilkan kebocoran.)

Menggunakan Java VisualVM

Dengan Java VisualVM, kita dapat memonitor memori Java Heap dan mengidentifikasi apakah perilakunya menunjukkan kebocoran memori.

Berikut adalah representasi grafis dari Java Heap analyzer MemLeak setelah inisialisasi (ingat diskusi kami tentang berbagai generasi):

pantau kebocoran memori menggunakan java visualvm

Setelah hanya 30 detik, Generasi Lama hampir penuh, menunjukkan bahwa, bahkan dengan GC Penuh, Generasi Lama terus berkembang, tanda yang jelas dari kebocoran memori.

Salah satu cara untuk mendeteksi penyebab kebocoran ini ditunjukkan pada gambar berikut ( klik untuk memperbesar ), yang dibuat menggunakan Java VisualVM dengan heapdump . Di sini, kita melihat bahwa 50% dari objek Hashtable$Entry berada di heap , sedangkan baris kedua mengarahkan kita ke kelas MemLeak . Jadi, kebocoran memori disebabkan oleh tabel hash yang digunakan dalam kelas MemLeak .

kebocoran memori tabel hash

Terakhir, amati Java Heap tepat setelah OutOfMemoryError kami di mana generasi Muda dan Tua benar-benar penuh .

kesalahan kehabisan memori

Kesimpulan

Kebocoran memori adalah salah satu masalah aplikasi Java yang paling sulit untuk diselesaikan, karena gejalanya bervariasi dan sulit untuk direproduksi. Di sini, kami telah menguraikan pendekatan langkah demi langkah untuk menemukan kebocoran memori dan mengidentifikasi sumbernya. Namun yang terpenting, baca pesan kesalahan Anda dengan cermat dan perhatikan jejak tumpukan Anda—tidak semua kebocoran sesederhana yang terlihat.

Lampiran

Selain Java VisualVM, ada beberapa alat lain yang dapat melakukan deteksi kebocoran memori. Banyak detektor kebocoran beroperasi di tingkat perpustakaan dengan mencegat panggilan ke rutinitas manajemen memori. Misalnya, HPROF , adalah alat baris perintah sederhana yang dibundel dengan Java 2 Platform Standard Edition (J2SE) untuk heap dan profil CPU. Output dari HPROF dapat dianalisa secara langsung atau digunakan sebagai input untuk tools lain seperti JHAT . Saat kami bekerja dengan aplikasi Java 2 Enterprise Edition (J2EE), ada sejumlah solusi penganalisis heap dump yang lebih ramah, seperti server aplikasi IBM Heapdumps untuk Websphere.