Java WeakHashMap指南

概述

在这篇文章中,我们将探索 java.util 包中的WeakHashMap

为了理解数据结构,我们将在这里使用它来推出一个简单的缓存实现。但是,请记住,这是为了了解地图的工作原理,并且创建自己的缓存实现几乎总是一个坏主意。

简而言之,WeakHashMap是Map接口的基于哈希表的实现,其键为WeakReference类型。

当WeakHashMap中的某个条目不再被普通使用时,该条目将被自动删除,这意味着没有单个Reference 指向该键。当垃圾回收(GC)进程丢弃某个键时,其条目将有效地从映射中删除,因此此类的行为与其他Map实现有所不同。

Strong, Soft, and Weak References

要了解WeakHashMap的工作原理,我们需要查看WeakReference类 -这是WeakHashMap实现中键的基本构造。在Java中,我们有三种主要的引用类型,我们将在以下各节中进行解释。

强引用

强引用是我们在日常编程中使用的最常见的引用类型:

Integer prime = 1;
变量prime具有对值为1 的Integer对象的强引用。任何具有指向其的强引用的对象均不适合使用GC。

弱引用

简而言之,只有在JVM绝对需要内存之前,才会对具有SoftReference 指向该对象的对象进行垃圾回收。

让我们看看如何在Java中创建SoftReference:

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

该主要对象有指向它很强的借鉴意义。

接下来,我们将主要的强引用包装为软引用。将强引用设为null之后,素对象可以使用GC,但仅在JVM绝对需要内存时才收集该对象。

虚引用

仅弱引用所引用的对象会被紧急收集;在这种情况下,GC不会等到需要内存。

我们可以通过以下方式在Java中创建WeakReference:

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

当我们将主要引用设为null时,主要对象将在下一个GC周期中被垃圾回收,因为没有其他强引用指向该对象。

WeakReference类型的引用在WeakHashMap中用作键。

WeakHashMap作为高效的内存缓存

假设我们要建立一个缓存,将大图像对象保留为值,并将图像名称保留为键。我们想选择一个合适的地图实现来解决该问题。

使用简单的HashMap将不是一个好的选择,因为值对象可能会占用大量内存。而且,即使它们不再在我们的应用程序中使用,它们也永远不会被GC进程从缓存中回收。

理想情况下,我们需要一个Map实现,该实现允许GC自动删除未使用的对象。当我们的应用程序中任何地方都没有使用大图像对象的键时,该条目将从内存中删除。

幸运的是,WeakHashMap具有这些特征。让我们测试一下WeakHashMap并观察其行为:

WeakHashMap<UniqueImageName, BigImage> 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);

我们正在创建一个WeakHashMap实例,该实例将存储我们的BigImage对象。我们将BigImage对象作为值,并将imageName对象引用作为键。的imageName将被存储在一个图作为WeakReference的类型。

接下来,我们将imageName引用设置为null,因此不再有指向bigImage对象的引用。WeakHashMap的默认行为是在下一个GC上回收没有引用的条目,因此该条目将在下一个GC进程中从内存中删除。

我们正在调用System.gc()来强制JVM触发GC进程。GC周期结束后,我们的WeakHashMap将为空:

WeakHashMap<UniqueImageName, BigImage> 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));

请注意,只有imageNameFirst引用设置为null。该imageNameSecond参考保持不变。触发GC后,映射将仅包含一个条目– imageNameSecond。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cj96248

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值