Apakah ada cara untuk membebaskan memori di Jawa, mirip dengan free()
fungsi C ? Atau apakah mengatur objek ke nol dan mengandalkan GC satu-satunya opsi?
Apakah ada cara untuk membebaskan memori di Jawa, mirip dengan free()
fungsi C ? Atau apakah mengatur objek ke nol dan mengandalkan GC satu-satunya opsi?
Jawaban:
Java menggunakan memori yang dikelola, jadi satu-satunya cara Anda dapat mengalokasikan memori adalah dengan menggunakan new
operator, dan satu-satunya cara Anda dapat mengalokasikan memori adalah dengan mengandalkan pengumpul sampah.
Whitepaper manajemen memori ini (PDF) dapat membantu menjelaskan apa yang terjadi.
Anda juga dapat menelepon System.gc()
untuk menyarankan agar pengumpul sampah segera beroperasi. Namun, Java Runtime membuat keputusan akhir, bukan kode Anda.
Menurut dokumentasi Java ,
Memanggil metode gc menunjukkan bahwa Java Virtual Machine mengeluarkan upaya untuk mendaur ulang objek yang tidak digunakan untuk membuat memori yang mereka tempati saat ini tersedia untuk digunakan kembali dengan cepat. Ketika kontrol kembali dari pemanggilan metode, Java Virtual Machine telah melakukan upaya terbaik untuk merebut kembali ruang dari semua objek yang dibuang.
System.gc()
sepenuhnya.
Tidak ada yang tampaknya telah menyebutkan secara eksplisit mengatur referensi objek null
, yang merupakan teknik yang sah untuk "membebaskan" memori yang mungkin ingin Anda pertimbangkan.
Misalnya, Anda menyatakan bahwa List<String>
pada awal metode yang tumbuh menjadi sangat besar, tetapi hanya diperlukan hingga separuh jalan melalui metode. Anda bisa pada titik ini mengatur referensi Daftar null
untuk memungkinkan pengumpul sampah untuk berpotensi mengklaim kembali objek ini sebelum metode selesai (dan referensi itu jatuh dari ruang lingkup tetap).
Perhatikan bahwa saya jarang menggunakan teknik ini dalam kenyataan tetapi perlu dipertimbangkan ketika berhadapan dengan struktur data yang sangat besar.
System.gc();
Menjalankan pemulung.
Memanggil metode gc menunjukkan bahwa Java Virtual Machine mengeluarkan upaya untuk mendaur ulang objek yang tidak digunakan untuk membuat memori yang mereka tempati saat ini tersedia untuk digunakan kembali dengan cepat. Ketika kontrol kembali dari pemanggilan metode, Java Virtual Machine telah melakukan upaya terbaik untuk merebut kembali ruang dari semua objek yang dibuang.
Tidak direkomendasikan.
Sunting: Saya menulis respons asli pada 2009. Sekarang 2015.
Pengumpul sampah semakin membaik dalam ~ 20 tahun di Jawa. Pada titik ini, jika Anda secara manual memanggil pengumpul sampah, Anda mungkin ingin mempertimbangkan pendekatan lain:
* "Saya pribadi mengandalkan variabel nulling sebagai pengganti untuk penghapusan yang tepat di masa depan. Misalnya, saya meluangkan waktu untuk membatalkan semua elemen array sebelum benar-benar menghapus (membuat null) array itu sendiri."
Ini tidak perlu. Cara kerja Java GC adalah ia menemukan objek yang tidak memiliki referensi padanya, jadi jika saya memiliki Obyek x dengan referensi (= variabel) a yang menunjuk padanya, GC tidak akan menghapusnya, karena ada referensi ke objek itu:
a -> x
Jika Anda batal dari ini terjadi:
a -> null
x
Jadi sekarang x tidak memiliki referensi yang menunjuk ke sana dan akan dihapus. Hal yang sama terjadi ketika Anda mengatur referensi ke objek yang berbeda dari x.
Jadi jika Anda memiliki array array yang merujuk ke objek x, y dan z dan variabel a yang merujuk ke array, tampilannya seperti itu:
a -> arr -> x
-> y
-> z
Jika Anda batal dari ini terjadi:
a -> null
arr -> x
-> y
-> z
Jadi GC menemukan arr tidak memiliki referensi yang ditetapkan dan menghapusnya, yang memberi Anda struktur ini:
a -> null
x
y
z
Sekarang GC menemukan x, y dan z dan menghapusnya juga. Menghapus setiap referensi dalam array tidak akan membuat sesuatu yang lebih baik, itu hanya akan menggunakan waktu dan ruang CPU dalam kode (yang mengatakan, tidak akan ada salahnya lebih jauh dari itu. GC masih akan dapat melakukan cara yang seharusnya ).
Alasan yang sah untuk ingin membebaskan memori dari program apa pun (java atau tidak) adalah untuk membuat lebih banyak memori tersedia untuk program lain pada tingkat sistem operasi. Jika aplikasi java saya menggunakan 250MB saya mungkin ingin memaksanya turun ke 1MB dan membuat 249MB tersedia untuk aplikasi lain.
Untuk memperluas jawaban dan komentar oleh Yiannis Xanthopoulos dan Hot Licks (maaf, saya belum bisa berkomentar!), Anda dapat mengatur opsi VM seperti contoh ini:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
Dalam jdk 7 saya ini kemudian akan melepaskan memori VM yang tidak digunakan jika lebih dari 30% dari tumpukan menjadi bebas setelah GC ketika VM idle. Anda mungkin perlu menyetel parameter ini.
Walaupun saya tidak melihatnya ditekankan pada tautan di bawah, perhatikan bahwa beberapa pemulung mungkin tidak mematuhi parameter ini dan secara default java dapat memilih salah satu dari ini untuk Anda, seandainya Anda memiliki lebih dari satu inti (maka argumen UseG1GC di atas ).
Pembaruan: Untuk java 1.8.0_73 Saya telah melihat JVM sesekali melepaskan jumlah kecil dengan pengaturan default. Tampaknya hanya melakukannya jika ~ 70% dari heap tidak digunakan .. tidak tahu apakah akan lebih agresif melepaskan jika OS pada memori fisik rendah.
Saya sudah melakukan eksperimen tentang ini.
Memang benar bahwa System.gc();
hanya menyarankan untuk menjalankan Pengumpul Sampah.
Tetapi memanggil System.gc();
setelah mengatur semua referensi null
, akan meningkatkan kinerja dan pekerjaan memori.
Jika Anda benar-benar ingin mengalokasikan dan membebaskan blok memori, Anda dapat melakukan ini dengan ByteBuffers langsung. Bahkan ada cara non-portabel untuk membebaskan memori.
Namun, seperti yang telah disarankan, hanya karena Anda harus membebaskan memori dalam C, bukan berarti itu ide yang baik untuk melakukan ini.
Jika Anda merasa memiliki kasus penggunaan yang baik gratis (), harap sertakan dalam pertanyaan sehingga kami dapat melihat apa yang ingin Anda lakukan, kemungkinan besar ada cara yang lebih baik.
Seluruhnya dari javacoffeebreak.com/faq/faq0012.html
Utas dengan prioritas rendah menangani pengumpulan sampah secara otomatis untuk pengguna. Selama waktu idle, utas dapat dipanggil, dan itu dapat mulai membebaskan memori yang sebelumnya dialokasikan untuk suatu objek di Jawa. Tapi jangan khawatir - itu tidak akan menghapus objek Anda!
Ketika tidak ada referensi ke suatu objek, itu menjadi permainan yang adil bagi pengumpul sampah. Daripada memanggil beberapa rutin (seperti gratis di C ++), Anda cukup menetapkan semua referensi ke objek ke nol, atau menetapkan kelas baru ke referensi.
Contoh:
public static void main(String args[]) { // Instantiate a large memory using class MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192); // Do some work for ( .............. ) { // Do some processing on myClass } // Clear reference to myClass myClass = null; // Continue processing, safe in the knowledge // that the garbage collector will reclaim myClass }
Jika kode Anda akan meminta sejumlah besar memori, Anda mungkin ingin meminta pengumpul sampah memulai ruang reklamasi, daripada membiarkannya melakukannya sebagai utas prioritas rendah. Untuk melakukan ini, tambahkan berikut ini ke kode Anda
System.gc();
Pengumpul sampah akan berusaha untuk mendapatkan kembali ruang kosong, dan aplikasi Anda dapat terus mengeksekusi, dengan sebanyak mungkin memori direklamasi (masalah fragmentasi memori mungkin berlaku pada platform tertentu).
Dalam kasus saya, karena kode Java saya dimaksudkan untuk porting ke bahasa lain dalam waktu dekat (Terutama C ++), saya setidaknya ingin membayar layanan bibir untuk mengosongkan memori dengan benar sehingga membantu proses porting nanti.
Saya pribadi mengandalkan variabel nulling sebagai pengganti untuk penghapusan yang tepat di masa depan. Sebagai contoh, saya meluangkan waktu untuk membatalkan semua elemen array sebelum benar-benar menghapus (membuat null) array itu sendiri.
Tapi kasus saya sangat khusus, dan saya tahu saya mendapat pukulan kinerja saat melakukan ini.
* "Misalnya, katakan Anda akan mendeklarasikan Daftar di awal metode yang ukurannya menjadi sangat besar, tetapi hanya diperlukan hingga separuh jalan melalui metode. Anda bisa pada titik ini menetapkan referensi Daftar ke nol untuk memungkinkan pemungut sampah untuk berpotensi mengklaim kembali objek ini sebelum metode selesai (dan referensi tetap berada di luar jangkauan). " *
Ini benar, tetapi solusi ini mungkin tidak dapat digeneralisasikan. Saat mengatur referensi objek Daftar ke null-akan- membuat memori tersedia untuk pengumpulan sampah, ini hanya berlaku untuk objek Daftar tipe primitif. Jika objek Daftar bukan berisi tipe referensi, pengaturan objek List = null tidak akan dereference -any- dari tipe referensi yang terkandung -in- daftar. Dalam kasus ini, mengatur Daftar objek = null akan menjadi yatim jenis referensi yang terkandung yang objeknya tidak akan tersedia untuk pengumpulan sampah kecuali algoritma pengumpulan sampah cukup pintar untuk menentukan bahwa objek telah yatim piatu.
Algress java menyediakan pengumpulan sampah otomatis kadang-kadang Anda ingin tahu seberapa besar objek itu dan berapa banyak yang tersisa. Memori bebas menggunakan secara terprogram import java.lang;
dan Runtime r=Runtime.getRuntime();
untuk mendapatkan nilai memori yang digunakan mem1=r.freeMemory();
untuk membebaskan memori, panggil r.gc();
metode dan panggilanfreeMemory()
Rekomendasi dari JAVA adalah menetapkan untuk null
Dari https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
Menetapkan nilai nol ke variabel yang tidak lagi diperlukan secara eksplisit membantu pengumpul sampah untuk mengidentifikasi bagian-bagian memori yang dapat direklamasi dengan aman. Meskipun Java menyediakan manajemen memori, itu tidak mencegah kebocoran memori atau menggunakan jumlah memori yang berlebihan.
Aplikasi dapat menyebabkan kebocoran memori dengan tidak merilis referensi objek. Melakukan hal itu mencegah pengumpul sampah Java dari merebut kembali benda-benda itu, dan menghasilkan peningkatan jumlah memori yang digunakan. Secara eksplisit membatalkan referensi ke variabel setelah penggunaannya memungkinkan pengumpul sampah untuk mendapatkan kembali memori.
Salah satu cara untuk mendeteksi kebocoran memori adalah dengan menggunakan alat profil dan mengambil snapshot memori setelah setiap transaksi. Aplikasi bebas kebocoran dalam kondisi mapan akan menampilkan memori tumpukan aktif yang stabil setelah pengumpulan sampah.