什么时候使用WeakHashMap或者WeakReference?

时间:2020-03-06 14:56:39  来源:igfitidea点击:

使用弱引用是我从未见过的实现方式,因此我试图弄清它们的用例以及实现的工作方式。我们何时需要使用WeakHashMap或者WeakReference,它是如何使用的?

解决方案

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

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

One problem with strong references is
  caching, particular with very large
  structures like images. Suppose you
  have an application which has to work
  with user-supplied images, like the
  web site design tool I work on.
  Naturally you want to cache these
  images, because loading them from disk
  is very expensive and you want to
  avoid the possibility of having two
  copies of the (potentially gigantic)
  image in memory at once.
  
  Because an image cache is supposed to
  prevent us from reloading images when
  we don't absolutely need to, you will
  quickly realize that the cache should
  always contain a reference to any
  image which is already in memory. With
  ordinary strong references, though,
  that reference itself will force the
  image to remain in memory, which
  requires you to somehow determine when
  the image is no longer needed in
  memory and remove it from the cache,
  so that it becomes eligible for
  garbage collection. You are forced to
  duplicate the behavior of the garbage
  collector and manually determine
  whether or not an object should be in
  memory.

理解弱引用,伊桑·尼古拉斯(Ethan Nicholas)

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

我们可以使用weakhashmap来实现用于扩展对象创建的无资源缓存。

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

我在Google代码中搜索了" new WeakHashMap()"。

我从GNU classpath项目获得了一堆火柴,

  • Apache xbean项目:WeakHashMapEditor.java
  • Apache Lucene项目:CachingWrapperFilter.java

这篇博客文章演示了这两个类的用法: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中进行了介绍。

一个明显的区别是" WeakReference"和" SoftReference"之间的区别。

基本上,一旦被引用的对象没有对它的硬引用,JVM就会急切地对它进行" WeakReference" GC-d处理。另一方面,SoftReferenced对象往往会被垃圾收集器留下,直到它确实需要回收内存为止。

将值保存在WeakReference中的缓存将毫无用处(在WeakHashMap中,是弱引用的键)。当我们想要实现一个可以随着可用内存而增长和缩小的缓存时,SoftReferences对于包装这些值很有用。

如上所述,只要存在强参考,就保持弱参考。

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

如上所述,在与听众一起玩耍时,我们迅速意识到,从用户的角度来看,对象是"立即"收集的。

特别是WeakReference和WeakHashMap的一种常见用法是为对象添加属性。有时,我们想向对象添加一些功能或者数据,但是子类化和/或者合成不是一种选择,在这种情况下,显而易见的事情是创建一个将我们要扩展的对象链接到要添加的属性的哈希映射。 。然后只要我们需要该属性,就可以在地图中查找它。但是,如果要添加属性的对象倾向于被破坏和创建很多,则可能导致地图中的许多旧对象占用大量内存。

如果使用WeakHashMap,则对象将在程序的其余部分不再使用它们后立即离开地图,这是理想的行为。

我必须这样做才能向java.awt.Component中添加一些数据,以解决JRE在1.4.2和1.5之间的变化,我可以通过将我感兴趣的每个组件都归类为int(JButtonJFrameJPanel....),但是用更少的代码就容易得多。