Java 中 SoftReference 和 WeakReference 有什么区别?

29 浏览
0 Comments

Java 中 SoftReference 和 WeakReference 有什么区别?

java.lang.ref.WeakReference和java.lang.ref.SoftReference有什么区别?

admin 更改状态以发布 2023年5月22日
0
0 Comments

弱引用是主动回收的。如果垃圾回收发现一个对象只能通过弱引用到达(仅通过弱引用可达),它将立即清除指向该对象的弱引用。因此,它们适用于在程序中想要保留对象的引用以及与之关联的(强引用)“相关信息”的情况,例如一个类的缓存反射信息,或者一个对象的包装器等。任何在对象被GC后无需保留的东西都是无意义的。当弱引用被清除时,它会被排入某处代码轮询的引用队列,并且它也会丢弃关联对象。也就是说,您可以保留有关对象的额外信息,但是一旦所引用的对象消失,这些信息就不再需要。实际上,在某些情况下,您甚至可以子类化WeakReference并将关联的额外信息保存在WeakReference子类的字段中。另一个典型的WeakReference用法是结合Maps使用来保留规范实例。

另一方面,软引用适用于缓存外部可重建资源,因为垃圾回收通常会延迟清除它们。不过有保证的是,在抛出OutOfMemoryError之前,所有的SoftReferences都将被清除,因此理论上它们不能引起OOME [*]。

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

现在对于[*]。保留SoftReference本身不会引起OOME。另一方面,如果您误用SoftReference执行一个WeakReference应该执行的任务(即,当Reference对象被清除时,您会强引用与对象相关的信息,并将其丢弃),则可能会遇到OOME,因为您轮询ReferenceQueue并丢弃相关对象的代码可能不及时运行。

因此,决策取决于用途
- 如果您正在缓存昂贵构造但是可从其他数据重建的信息,请使用软引用
- 如果您正在保持对一些数据的规范实例的引用,或者您想要对一个对象进行引用而又不“拥有”它(从而防止其被GC),请使用弱引用。

0
0 Comments

摘自Ethan Nicholas的《理解弱引用》文章:

弱引用

简单地说,弱引用就是一个引用,它不足以强制一个对象保持在内存中。弱引用允许你利用垃圾收集器自动确定对象可达性,因此你不必自己来完成。创建弱引用的方式如下:

WeakReference weakWidget = new WeakReference(widget);

然后在代码的其他地方,你可以使用weakWidget.get()方法来获取实际的Widget对象。当然,如果没有强引用指向该小部件,因为弱引用不足以防止垃圾收集,你可能会发现weakWidget.get()突然开始返回null

...

软引用

软引用与弱引用完全相同,只是它不太热衷于丢弃所引用的对象。只有在下一次垃圾回收周期中,只有弱引用链接着的对象会被丢弃,但在柔性引用链接着的对象通常会被保留一段时间。

SoftReferences不一定要与WeakReferences有所不同,但实际上,柔性引用的对象通常会在内存充足的情况下保留。这使得它们成为缓存的一个极好的基础,例如上面描述的图像缓存,因为你可以让垃圾收集器担心对象的可达性(一个强连对象将永远不会从缓存中删除)和它们消耗的内存有多么严重。

Peter Kessler在一条评论中补充道:

Sun JRE对软引用和弱引用的处理是不同的。如果可用内存没有压力,我们会尝试保留软引用引用的对象。需要注意的一个细节是:"-client"和"-server" JRE的策略是不同的:-client JRE会优先清除软引用以使你的内存占用最小化,而-server JRE则会尽可能扩大堆空间而非清除软引用以保持性能的最大化。这并不是一种适合所有情况的策略。

0