166

弱引用的使用是我从未见过的实现,所以我试图弄清楚它们的用例是什么以及实现如何工作。你什么时候需要使用WeakHashMaporWeakReference以及它是如何使用的?

4

10 回答 10

96

强引用的一个问题是缓存,尤其是像图像这样非常大的结构。假设您有一个必须处理用户提供的图像的应用程序,例如我使用的网站设计工具。当然,您希望缓存这些图像,因为从磁盘加载它们非常昂贵,并且您希望避免一次在内存中拥有两个(可能是巨大的)图像副本的可能性。

因为图像缓存应该防止我们在绝对不需要时重新加载图像,所以您很快就会意识到缓存应该始终包含对任何已经在内存中的图像的引用。但是,对于普通的强引用,该引用本身将强制图像保留在内存中,这需要您以某种方式确定内存中何时不再需要图像并将其从缓存中删除,以便它可以进行垃圾回收。您被迫复制垃圾收集器的行为并手动确定对象是否应该在内存中。

理解弱引用,Ethan Nicholas

于 2008-09-30T20:09:11.647 回答
59

WeakReference相对SoftReference

要明确的一个区别是 aWeakReference和 a之间的区别SoftReference

基本上,一旦被引用的对象没有对它的引用,JVMWeakReference就会急切地进行GC-d。另一方面,一个d 对象往往会被垃圾收集器留下,直到它真的需要回收内存。SoftReference

将值保存在s中的缓存WeakReference将毫无用处(在 a 中WeakHashMap,它是弱引用的键)。SoftReferences当您想要实现一个可以随可用内存增长和缩小的缓存时,将值包装起来很有用。

于 2008-09-30T23:00:08.333 回答
30

WeakReferences 和s 的一种常见用途WeakHashMap是向对象添加属性。有时您想向对象添加一些功能或数据,但子类化和/或组合不是一种选择,在这种情况下,显而易见的事情是创建一个哈希图,将您想要扩展的对象链接到您想要添加的属性. 然后,每当您需要该属性时,您都可以在地图中查找它。但是,如果您要添加属性的对象往往会被销毁和创建很多,那么最终您的地图中可能会有很多旧对象占用大量内存。

如果您使用 aWeakHashMap代替,对象将在您的程序的其余部分不再使用它们时立即离开您的地图,这是所需的行为。

我必须这样做来添加一些数据来java.awt.Component解决 JRE 在 1.4.2 和 1.5 之间的变化,我可以通过子类化我感兴趣的每个组件来修复它 int ( JButton, JFrame, JPanel....) 但这太多了用更少的代码更容易。

于 2008-10-15T15:17:03.373 回答
22

另一个有用的例子WeakHashMapWeakReference监听器注册实现

当你创建想要监听某些事件的东西时,通常你注册一个监听器,例如

manager.registerListener(myListenerImpl);

如果manager将您的侦听器存储在 aWeakReference中,则意味着您不需要删除寄存器,例如使用 a manager.removeListener(myListenerImpl),因为一旦您的侦听器或持有该侦听器的组件变得不可用,它将自动删除。

当然你仍然可以手动删除你的监听器,但是如果你不这样做或者你忘记了它,它不会导致内存泄漏,也不会阻止你的监听器被垃圾回收。

出现在哪里WeakHashMap

想要将注册的监听器存储为WeakReferences 的监听器注册表需要一个集合来存储这些引用。标准 Java 库中没有WeakHashSet实现,WeakHashMap但我们可以轻松地使用后者来“实现”第一个的功能:

Set<ListenerType> listenerSet =
    Collections.newSetFromMap(new WeakHashMap<ListenerType, Boolean>());

有了这个listenerSet来注册一个新的监听器,你只需要将它添加到集合中,即使它没有被显式删除,如果不再引用监听器,它也会被 JVM 自动删除。

于 2014-08-11T11:18:11.177 回答
5

这篇博文演示了这两个类的使用: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 的对象进行同步。要求是:

  • 必须返回对同一对象的引用才能同时使用等效 ID
  • 必须为不同的 ID 返回不同的对象
  • 无释放机制(对象不返回给提供者)
  • 不得泄漏(未使用的对象有资格进行垃圾收集)

这是使用以下类型的内部存储映射来实现的:

WeakHashMap<Mutex, WeakReference<Mutex>>

对象既是键又是值。当地图外部的任何东西都没有对该对象的硬引用时,它可以被垃圾收集。映射中的值与硬引用一起存储,因此必须将值包装在WeakReference中以防止内存泄漏。最后一点包含在javadoc中。

于 2008-09-30T22:05:10.057 回答
3

例如,如果您想跟踪某个类创建的所有对象。为了仍然允许这些对象被垃圾收集,您保留对对象而不是对象本身的弱引用列表/映射。

现在,如果有人可以向我解释幻影引用,我会很高兴......

于 2008-09-30T20:05:13.450 回答
3

如上所述,只要存在强引用,就会保留弱引用。

一个示例用法是在侦听器内部使用 Wea​​kReference,这样一旦对其目标对象的主要引用消失,侦听器就不再处于活动状态。请注意,这并不意味着 WeakReference 已从侦听器列表中删除,仍然需要进行清理,但可以执行清理,例如,在预定时间执行。这也有防止被监听的对象持有强引用的效果,并最终成为内存膨胀的来源。示例:Swing GUI 组件引用具有比窗口更长生命周期的模型。

在如上所述与听众玩耍时,我们很快意识到从用户的角度“立即”收集对象。

于 2008-10-01T07:53:00.440 回答
2

我对 WeakReferences 的一个实际用途是,如果您有一个很少使用的非常大的对象。您不想在不需要时将其保存在内存中;但是,如果另一个线程需要相同的对象,您也不希望其中两个在内存中。您可以在某处保留对对象的弱引用,并在使用它的方法中保留硬引用;当方法都完成时,对象将被收集。

于 2008-09-30T20:09:36.920 回答
1

我对“new WeakHashMap()”进行了谷歌代码搜索。

我从 GNU 类路径项目中得到了一堆匹配项

  1. Apache xbean 项目:WeakHashMapEditor.java
  2. Apache Lucene 项目:CachingWrapperFilter.java
于 2008-09-30T21:52:23.223 回答
-1

您可以使用weakhashmap 为扩展对象创建实现无资源缓存。

但请注意,拥有可变对象是不可取的。我用它来缓存查询结果(执行大约需要 400 毫秒)到一个很少更新的文本搜索引擎。

于 2008-09-30T20:28:42.817 回答