Panduan WeakHashMap di Java

1. Gambaran keseluruhan

Dalam artikel ini, kita akan melihat WeakHashMap dari pakej java.util .

Untuk memahami struktur data, kami akan menggunakannya di sini untuk melancarkan pelaksanaan cache yang mudah. Namun, ingatlah bahawa ini dimaksudkan untuk memahami bagaimana peta berfungsi, dan membuat pelaksanaan cache anda sendiri selalu merupakan idea yang buruk.

Ringkasnya, WeakHashMap adalah implementasi berasaskan hashtable antara muka Peta , dengan kunci yang jenis WeakReference .

Entri dalam WeakHashMap akan dikeluarkan secara automatik apabila kuncinya tidak lagi digunakan, yang bermaksud bahawa tidak ada satu Rujukan yang menunjukkan kunci itu. Apabila proses pengumpulan sampah (GC) membuang kunci, kemasukannya dikeluarkan dengan berkesan dari peta, jadi kelas ini berkelakuan agak berbeza dari pelaksanaan Peta lain .

2. Rujukan yang Kuat, Lembut, dan Lemah

Untuk memahami bagaimana WeakHashMap berfungsi, kita perlu melihat kelas WeakReference - yang merupakan konstruk asas untuk kunci dalam pelaksanaan WeakHashMap . Di Jawa, kami mempunyai tiga jenis rujukan utama, yang akan kami jelaskan di bahagian berikut.

2.1. Rujukan yang kuat

Rujukan yang kuat adalah jenis Rujukan yang paling biasa yang kita gunakan dalam pengaturcaraan harian kita:

Integer prime = 1;

Pembolehubah perdana mempunyai rujukan yang kuat terhadap objek Integer dengan nilai 1. Mana-mana objek yang mempunyai rujukan kuat yang menunjuk ke arahnya tidak layak untuk GC.

2.2. Rujukan Lembut

Ringkasnya, objek yang mempunyai SoftReference menunjuknya tidak akan dikumpulkan sampah sehingga JVM benar-benar memerlukan memori.

Mari lihat bagaimana kita dapat membuat SoftReference di Java:

Integer prime = 1; SoftReference soft = new SoftReference(prime); prime = null;

The Perdana objek mempunyai rujukan yang kuat menunjuk kepadanya.

Seterusnya, kami membungkus rujukan kuat perdana menjadi rujukan lembut. Selepas membuat bahawa rujukan kuat null , seorang Perdana objek layak untuk GC tetapi akan diambil hanya apabila benar-benar perlu JVM ingatan.

2.3. Rujukan Lemah

Objek yang hanya dirujuk oleh rujukan lemah adalah sampah yang dikumpulkan dengan penuh semangat; GC tidak akan menunggu sehingga memerlukan memori dalam kes itu.

Kita dapat membuat WeakReference di Java dengan cara berikut:

Integer prime = 1; WeakReference soft = new WeakReference(prime); prime = null;

Ketika kami membuat nol rujukan utama , objek utama akan dikumpulkan sampah pada kitaran GC berikutnya, kerana tidak ada rujukan kuat lainnya yang menunjuk ke sana.

Rujukan jenis WeakReference digunakan sebagai kunci dalam WeakHashMap .

3. WeakHashMap sebagai Cache Memori yang Cekap

Katakan bahawa kita ingin membina cache yang menjadikan objek gambar besar sebagai nilai, dan nama gambar sebagai kunci. Kami ingin memilih pelaksanaan peta yang tepat untuk menyelesaikan masalah itu.

Menggunakan HashMap yang sederhana tidak akan menjadi pilihan yang baik kerana objek nilai mungkin banyak memori. Lebih-lebih lagi, mereka tidak akan dituntut dari cache melalui proses GC, walaupun tidak lagi digunakan dalam aplikasi kami.

Sebaik-baiknya, kami mahukan implementasi Peta yang membolehkan GC menghapus objek yang tidak digunakan secara automatik. Apabila kunci objek gambar besar tidak digunakan dalam aplikasi kami di mana-mana tempat, entri itu akan dihapus dari memori.

Nasib baik, WeakHashMap mempunyai ciri-ciri ini. Mari uji WeakHashMap kami dan lihat bagaimana kelakuannya:

WeakHashMap map = new WeakHashMap(); BigImage bigImage = new BigImage("image_id"); UniqueImageName imageName = new UniqueImageName("name_of_big_image"); map.put(imageName, bigImage); assertTrue(map.containsKey(imageName)); imageName = null; System.gc(); await().atMost(10, TimeUnit.SECONDS).until(map::isEmpty);

Kami membuat instance WeakHashMap yang akan menyimpan objek BigImage kami . Kami meletakkan objek BigImage sebagai nilai dan rujukan objek imageName sebagai kunci. The imageName akan disimpan di dalam peta sebagai WeakReference jenis.

Seterusnya, kami menetapkan rujukan imageName menjadi nol , oleh itu tidak ada lagi rujukan yang menunjuk ke objek bigImage . Tingkah laku lalai dari WeakHashMap adalah menuntut semula entri yang tidak mempunyai rujukan pada GC seterusnya, jadi entri ini akan dihapus dari memori oleh proses GC berikutnya.

Kami memanggil System.gc () untuk memaksa JVM untuk mencetuskan proses GC. Selepas kitaran GC, WeakHashMap kami akan kosong:

WeakHashMap map = new WeakHashMap(); BigImage bigImageFirst = new BigImage("foo"); UniqueImageName imageNameFirst = new UniqueImageName("name_of_big_image"); BigImage bigImageSecond = new BigImage("foo_2"); UniqueImageName imageNameSecond = new UniqueImageName("name_of_big_image_2"); map.put(imageNameFirst, bigImageFirst); map.put(imageNameSecond, bigImageSecond); assertTrue(map.containsKey(imageNameFirst)); assertTrue(map.containsKey(imageNameSecond)); imageNameFirst = null; System.gc(); await().atMost(10, TimeUnit.SECONDS) .until(() -> map.size() == 1); await().atMost(10, TimeUnit.SECONDS) .until(() -> map.containsKey(imageNameSecond));

Perhatikan bahawa hanya rujukan imageNameFirst yang ditetapkan untuk nol . The imageNameSecond rujukan masih tidak berubah. Setelah GC dipicu, peta hanya akan mengandungi satu entri - imageNameSecond .

4. Kesimpulan

Dalam artikel ini, kami melihat jenis rujukan di Java untuk memahami sepenuhnya bagaimana java.util. WeakHashMap berfungsi. Kami membuat cache sederhana yang memanfaatkan tingkah laku WeakHashMap dan menguji apakah ia berfungsi seperti yang kami harapkan.

Pelaksanaan semua contoh dan cuplikan kod ini terdapat dalam projek GitHub - yang merupakan projek Maven, jadi mudah untuk diimport dan dijalankan sebagaimana adanya.