27

SoftReference确实只有WeakReference在创建为实例变量时才有帮助?在方法范围内使用它们有什么好处吗?

另一大部分是ReferenceQueue。除了能够跟踪哪些引用被确定为垃圾之外,还Reference.enqueue()可以用来强制注册一个对象进行垃圾回收吗?

例如,是否值得创建一个在对象中占用大量内存资源(由强引用持有)并创建引用以将它们排入队列的方法?

Object bigObject;
public void dispose() {
    ReferenceQueue<Object> queue = new ReferenceQueue<Object>();
    WeakReference<Object> ref = new WeakReference<Object>(bigObject, queue);
    bigObject = null;
    ref.enqueue();
}

(想象一下,在这种情况下,Object 代表一个使用大量内存的对象类型……比如BufferedImage什么)

这有什么现实效果吗?或者这只是浪费代码?

4

4 回答 4

36

引用队列的一个常见习惯用法是,例如子类WeakReference化以附加清理事物所需的信息,然后轮询 aReferenceQueue以获取清理任务。

ReferenceQueue<Foo> fooQueue = new ReferenceQueue<Foo>();

class ReferenceWithCleanup extends WeakReference<Foo> {
  Bar bar;
  ReferenceWithCleanup(Foo foo, Bar bar) {
    super(foo, fooQueue);
    this.bar = bar;
  }
  public void cleanUp() {
    bar.cleanUp();
  }
}

public Thread cleanupThread = new Thread() {
  public void run() {
    while(true) {
      ReferenceWithCleanup ref = (ReferenceWithCleanup)fooQueue.remove();
      ref.cleanUp();
    }
  }
}

public void doStuff() {
  cleanupThread.start();
  Foo foo = new Foo();
  Bar bar = new Bar();
  ReferenceWithCleanup ref = new ReferenceWithCleanup(foo, bar);
  ... // From now on, once you release all non-weak references to foo,
      // then at some indeterminate point in the future, bar.cleanUp() will
      // be run. You can force it by calling ref.enqueue().
}

例如,CacheBuilderweakKeys被选中时,Guava 实现的内部使用这种方法。

于 2013-01-22T02:38:49.473 回答
7

如果一个对象只有WeakReferences (或没有任何引用!)指向它,那么只要 Java 需要在内存中腾出更多空间,它就可以被垃圾收集。所以,WeakReference只要你希望一个对象保留在内存中,你就可以使用 s,但你不需要它保持那么糟糕(例如,如果 Java 需要垃圾收集它,没问题,你可以同时以某种方式取回它Java有更好的性能)

排队 aWeakReference允许您迭代ReferenceQueue并确定哪些引用已被垃圾收集,哪些没有。仅此而已 - 所以只有在您需要知道这一点时才这样做。

阅读更多: http ://weblogs.java.net/blog/2006/05/04/understanding-weak-references

于 2013-01-22T02:24:32.473 回答
5

一件常见的事情是创建软引用的映射。

Map<String, SoftReference<BigThing>> cache = new HashMap<>();
Set<String> thingsIAmCurrentlyGetting = new HashSet<String>();
Object mutex = new Object();

BigThing getThing(String key) {
  synchronized(mutex) {
    while(thingsIAmCurrentlyGetting.contains(key)) {
      mutex.wait();
    }
    SoftReference<BigThing> ref = cache.get(key);
    BigThing bigThing = ref == null ? null : ref.get();
    if(bigThing != null) return bigThing;
    thingsIAmCurrentlyGetting.add(key);
  }

  BigThing bigThing = getBigThing(key); // this may take a while to run.

  synchronized(mutex) {
    cache.put(key, bigThing);
    thingsIAmCurrentlyGetting.remove(key);
    mutex.notifyAll();
  }

  return bigThing;
}

我在这里展示我的老学校——新的 java 包可能有更简洁的方法来做到这一点。

于 2014-04-26T13:43:24.363 回答
1

不知道这里的问题是什么,但是:

1) soft ref 尽量保持引用,直到 jvm 真的真的需要内存。非常适合缓存,尤其是 LRU 缓存。看看 Guava 中的许多例子。

2)weak ref 不要试图阻止 gc 释放对象。如果您想知道该对象是否仍在某处使用,则使用它们。例如,它们用于存储有关线程和类的信息,因此当不再使用线程或类时,我们可以丢弃与之相关的元信息。

3) phantom ref 很弱,但不允许您引用实际对象。通过这种方式,您可以确保传递幻影无法恢复实际对象(这是弱参考的风险)。幻影参考也阻止要收集的对象,直到您清除参考。

ReferenceQueue:你不会在里面排队。gc 会为你做的。它们使您可以知道某些参考文献何时发布,而无需一一检查。

于 2017-08-25T10:23:38.797 回答