使用弱引用是我从未见过的实现方式,因此,我试图找出它们的用例以及实现的工作方式。您何时需要使用WeakHashMap
或WeakReference
,如何使用?
使用弱引用是我从未见过的实现方式,因此,我试图找出它们的用例以及实现的工作方式。您何时需要使用WeakHashMap
或WeakReference
,如何使用?
Answers:
强引用的一个问题是缓存,尤其是对于非常大的结构(如图像)而言。假设您有一个必须处理用户提供的图像的应用程序,例如我正在使用的网站设计工具。自然地,您想缓存这些图像,因为从磁盘加载它们非常昂贵,并且您希望避免一次在内存中拥有(可能是巨大的)图像的两个副本的可能性。
由于图像缓存应该阻止我们在绝对不需要时重新加载图像,因此您将很快意识到,缓存应始终包含对内存中已存在的任何图像的引用。但是,对于普通的强引用,该引用本身将迫使图像保留在内存中,这要求您以某种方式确定何时不再需要该图像,并将其从缓存中删除,从而使其有资格进行垃圾回收。您被迫复制垃圾回收器的行为,并手动确定对象是否应该在内存中。
理解弱引用,伊桑·尼古拉斯
WeakHashMap
。
WeakReference
与 SoftReference
一个明显的区别是a WeakReference
和a 之间的区别SoftReference
。
基本上是WeakReference
将GC-d的由JVM热切,一旦引用的对象没有难到它的引用。SoftReference
另一方面,垃圾收集器往往会留下一个d对象,直到它确实需要回收内存为止。
将值保存在WeakReference
s 内的缓存将毫无用处(在a中WeakHashMap
,是弱引用的键)。SoftReferences
当您要实现可随可用内存增长和收缩的缓存时,用于包装这些值很有用。
特别是WeakReference
s和WeakHashMap
s的一种常见用法是为对象添加属性。有时,您想向对象添加一些功能或数据,但是子类化和/或合成不是一种选择,在这种情况下,显而易见的事情是创建一个哈希图,将想要扩展的对象链接到要添加的属性。然后只要您需要该属性,就可以在地图中查找它。但是,如果要添加属性的对象往往会被破坏和创建很多,则最终可能会导致地图中的许多旧对象占用大量内存。
如果使用a WeakHashMap
代替,则对象将在程序的其余部分不再使用它们后立即离开地图,这是所需的行为。
我不得不这样做是为了增加一些数据,以java.awt.Component
避开在1.4.2和1.5之间的JRE的变化,我可以通过继承每个组件我很感兴趣,INT(固定它JButton
,JFrame
,JPanel
...),但是,这是多少更少的代码,更容易。
对于另一个有用的情况WeakHashMap
和WeakReference
是一个听众注册表实现。
当您创建想要监听某些事件的内容时,通常会注册一个监听器,例如
manager.registerListener(myListenerImpl);
如果用来manager
存储您的监听器WeakReference
,则意味着您不需要删除寄存器,例如使用,manager.removeListener(myListenerImpl)
因为一旦您的监听器或包含该监听器的组件不可用,该寄存器就会被自动删除。
当然,您仍然可以手动删除侦听器,但是如果您不删除它或忘记了它,则不会导致内存泄漏,也不会阻止您的侦听器被垃圾回收。
WeakHashMap
图片出现在哪里?
希望将WeakReference
s 存储为已注册侦听器的侦听器注册表需要一个集合来存储这些引用。WeakHashSet
标准Java库中没有任何实现,WeakHashMap
但是我们可以轻松地使用后者来“实现”第一个库的功能:
Set<ListenerType> listenerSet =
Collections.newSetFromMap(new WeakHashMap<ListenerType, Boolean>());
以此listenerSet
注册一个新的侦听器,您只需要将其添加到集合中,即使没有显式删除它,如果不再引用该侦听器,JVM也会自动将其删除。
WeakHashMap
是,每当需要一个HashMap
对象时。哇,您不必手动执行hashmap.remove ,因为一旦obj超出范围,项目就会自动删除!从字面上看是魔术!如此丑陋的魔术骇客简直就是一个完整的面孔。
WeakReference
大大简化了代码库,并避免了与无法取消订阅相关的不必要的错误。有什么缺点?
这篇博客文章演示了这两个类的用法:Java:在ID上同步。用法如下所示:
private static IdMutexProvider MUTEX_PROVIDER = new IdMutexProvider();
public void performTask(String resourceId) {
IdMutexProvider.Mutex mutext = MUTEX_PROVIDER.getMutex(resourceId);
synchronized (mutext) {
// look up the resource and do something with it
}
}
IdMutextProvider提供基于ID的对象进行同步。要求是:
这是通过使用以下类型的内部存储映射来实现的:
WeakHashMap<Mutex, WeakReference<Mutex>>
对象既是键又是值。当地图外部没有硬引用该对象时,可以对其进行垃圾回收。映射中的值与硬引用一起存储,因此必须将值包装在WeakReference中,以防止内存泄漏。最后一点在javadoc中进行了介绍。
例如,如果要跟踪某个类创建的所有对象。为了仍然允许对这些对象进行垃圾收集,请保留对对象的弱引用列表(而不是对象本身)。
现在如果有人可以向我解释幻影引用,我会很高兴...
如上所述,只要存在强参考,就保持弱参考。
一个示例用法是在侦听器内部使用WeakReference,以便一旦对目标对象的主要引用消失,侦听器将不再处于活动状态。请注意,这并不意味着WeakReference已从侦听器列表中删除,仍然需要进行清理,但可以在计划的时间执行清理。这还具有防止被侦听的对象持有强引用并最终成为内存膨胀的原因。示例:Swing GUI组件所引用的模型的生命周期比窗口长。
如上所述,在与听众一起玩耍时,我们迅速意识到,从用户的角度来看,对象是“立即”收集的。
我对WeakReferences的一种现实用途是,如果您有一个很少使用的非常大的单个对象。您不想在不需要时将其保留在内存中;但是,如果另一个线程需要相同的对象,则您也不希望其中两个在内存中。您可以在某个位置保留对对象的弱引用,并在使用该对象的方法中保留硬引用。当两个方法都完成时,将收集对象。
我在Google代码中搜索了“ new WeakHashMap()”。
我从GNU classpath项目获得了一堆火柴,
您可以使用weakhashmap来实现用于扩展对象创建的无资源缓存。
但请注意,并不需要具有可变的对象。我用它来将查询结果(执行大约需要400毫秒)缓存到一个文本搜索引擎,该引擎很少更新。