Java中的SoftReference和WeakReference有什么区别?


答案 1

摘自Ethan Nicholas的《Understanding Weak References》:

弱引用

简单地说,弱引用是一个不够强的引用,无法强制对象保留在内存中。弱引用允许您利用垃圾回收器的能力来确定可访问性,因此您不必自己动手。您可以创建一个弱引用,如下所示:

WeakReference weakWidget = new WeakReference(widget);

,然后使用代码中的其他位置来获取实际对象。当然,弱引用不够强大,无法防止垃圾回收,因此您可能会发现(如果没有对小部件的强引用)突然开始返回。weakWidget.get()WidgetweakWidget.get()null

...

软引用

软引用与弱引用完全相同,只是它不太急于丢弃它所引用的对象。一个只有弱可访问的对象(对它最强的引用)将在下一个垃圾回收周期中被丢弃,但是一个可软访问的对象通常会停留一段时间。WeakReferences

SoftReferences不需要与 的行为有任何不同,但在实践中,只要内存充足,就可以保留可软访问的对象。这使得它们成为缓存(例如上面描述的图像缓存)的良好基础,因为您可以让垃圾回收器担心对象的可访问性(强可访问的对象永远不会从缓存中删除)以及它需要它们消耗的内存的严重程度。WeakReferences

Peter Kessler在评论中补充道:

Sun JRE 确实将 SoftReferences 与 WeakReferences 区别对待。如果可用内存没有压力,我们尝试保留 SoftReference 引用的对象。一个细节:“-client”和“-server”JRE的策略是不同的:-client JRE试图通过清除SoftReferences而不是扩展堆来保持较小的占用空间,而-server JRE试图通过更愿意扩展堆(如果可能)而不是清除SoftReferences来保持较高的性能。一种尺寸并不适合所有人。


答案 2

弱引用被急切地收集。如果 GC 发现某个对象是弱可访问的(只能通过弱引用访问),它将立即清除对该对象的弱引用。因此,它们很适合保留对对象的引用,而您的程序还会保留(强烈引用的)“相关信息”,例如有关类的缓存反射信息或对象的包装器等。任何在与它关联的对象之后保留的无意义的东西都是GC-ed的。当弱引用被清除时,它会在代码轮询某处的引用队列中排队,并且它还会丢弃关联的对象。也就是说,您可以保留有关对象的额外信息,但是一旦它引用的对象消失,就不需要该信息。实际上,在某些情况下,您甚至可以对 WeakReference 进行子类,并将有关对象的相关额外信息保留在 WeakReference 子类的字段中。WeakReference的另一个典型用途是与Map结合使用来保留规范实例。

另一方面,SoftReference适用于缓存外部可重现资源,因为GC通常会延迟清除它们。但是可以保证,在抛出OutOfMemoryError之前,所有SoftReference都会被清除,因此从理论上讲,它们不能导致OOME[*]。

典型的用例示例是从文件中保留内容的解析形式。您将实现一个系统,您可以在其中加载文件,解析它,并保留对解析表示的根对象的 SoftReference。下次需要该文件时,将尝试通过 SoftReference 检索它。如果可以检索它,则无需执行另一次加载/解析,如果 GC 在此期间清除了它,则重新加载它。这样,您就可以利用可用内存进行性能优化,但不会冒 OOME 的风险。

现在是 [*]。保留 SoftReference 本身不会导致 OOME。另一方面,如果您错误地将 SoftReference 用于要使用弱引用的任务(即,您以某种方式保持与对象关联的信息,并在清除 Reference 对象时丢弃它),则可以遇到 OOME,因为轮询 ReferenceQueue 并丢弃关联对象的代码可能碰巧没有及时运行。

因此,决策取决于使用情况 - 如果您正在缓存构建成本高昂的信息,但仍然可以从其他数据中重建,请使用软引用 - 如果您要保留对某些数据的规范实例的引用,或者您希望在不“拥有”对象的情况下引用对象(从而防止它被GC'd),请使用弱引用。