Java:强/软/弱/幻象引用之间的区别


178

我已经阅读了有关该主题的这篇文章,但是我不太了解。描述概念时,请给我一些建议以及示例。



4
我已经阅读了该文档,但并不能帮助我想象有什么不同。(也许是因为这是一份难懂的文档)

14
如果您阅读该文章但仍然不了解,您是否对此有特定疑问?很难回答“请向我解释Foo”,“这是什么意思”,“我不明白”,而没有具体说明哪些地方没有得到。
yshavit 2012年


@LouisWasserman顶部链接不再有效。
Mehraj Malik

Answers:


142

Java提供了两种不同类型/类型的引用对象Strongweak。弱引用对象可以进一步分为softphantom

  • 强大
    • 柔软的
    • 幻影

让我们一点一点地走。

强参考对象

StringBuilder builder = new StringBuilder();

这是引用对象的默认类型/类,如果没有特别指定,则为:builder是强引用对象。这种引用使所引用的对象不符合GC的条件。也就是说,每当一个对象被一系列强引用对象引用时,就无法对其进行垃圾回收。

弱参考对象

WeakReference<StringBuilder> weakBuilder = new WeakReference<StringBuilder>(builder);

弱引用对象不是引用对象的默认类型/类,要使用它们,应像上面的示例一样明确指定它们。这种参考使参考对象有资格使用GC。也就是说,如果StringBuilder内存中对象唯一可访问的引用实际上是弱引用,则允许GC垃圾回收StringBuilder对象。如果只有弱引用对象可以访问内存中的对象,则该对象将自动具有GC资格。

弱点水平

可以列举两种不同的弱点级别:“ 软”和“ 幻像”

一个柔软的参考对象基本上是一个弱引用对象保留在内存多一点:通常情况下,它抵抗GC循环,直到没有可用的内存和存在的风险OutOfMemoryError(在这种情况下,它可以被删除)。

另一方面,幻影引用对象仅在确切地知道何时已将对象有效地从内存中删除时才有用:通常,它们用于修复怪异的finalize()复兴/复活行为,因为它们实际上并不返回对象本身,而是返回对象本身。仅有助于保持他们的记忆力

弱引用对象是实现缓存模块的理想选择。实际上,只要强引用链无法再访问对象/值,就可以通过允许GC清理内存区域来实现某种自动收回。一个示例是WeakHashMap保留弱键。


76

参考不足:

简而言之,弱引用是强度不足以迫使对象保留在内存中的引用。弱引用使您可以利用垃圾收集器的能力来确定您的可达性,因此您不必自己做。

软参考:

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

幻影参考:

幻像引用与SoftReference或WeakReference完全不同。它对它的对象的控制是如此的脆弱,以至于您甚至无法检索该对象-它的get()方法始终返回null。此类引用的唯一用途是跟踪何时将其排队到ReferenceQueue中,因为此时您知道指向的对象已死。

该文本摘自:https : //weblogs.java.net/blog/2006/05/04/understanding-weak-references


1
虽然此答案中的所有内容看起来都是正确的,但在我看来,链接的网页上可能还是有错误。程序包java.lang.refJavadoc和PhantomReference 的Javadoc建议在对象不再“幻影可达”之后才进行垃圾回收,这意味着(与SoftReference不同)PhantomReference必须在其引用的对象可以出队之前被出队。被垃圾回收...并且其被排队并不表示相关的内存已被释放。
西奥多·默多克

2
作为记录,我宁愿生活在该博客文章正确的世界中。
西奥多·默多克

1
@TheodoreMurdock Javadoc是正确的。幻像引用完全不会阻止垃圾回收。对象排队后,即使终结器已经运行,它也不能被终结器保存。它已经死了,但还没有消失。
Leliel

@Leliel实际上,幻像引用实际上在进入队列后确实会阻止垃圾回收...我最近才意识到这一点,当时有一个错误导致清理线程提前退出。幻像引用的存在足以确保每个幻像引用的对象都保留在我的堆转储中,无法收集...如果您无法处理队列,或者在处理队列时无法使幻像引用符合gc(并且不清除()幻像引用),那么您的内存泄漏将同时包括幻像引用和被引用的对象。
西奥多·默多克

25

SoftReference和之间的简单区别WeakReferenceAndroid Developer提供。

a SoftReference和a 之间的差异WeakReference是决定清除和排队引用的时间点:

  • SoftReference应尽快清除A 并使其入队,以防VM内存不足的危险。

  • WeakReference一旦已知弱引用,A 可能会被清除并入队。


16

您使用的三个术语主要与Object收集垃圾的资格有关。

弱引用 ::它的引用强度不足以迫使对象保留在内存中。它是垃圾收集器的一时冲动,以收集该对象进行垃圾收集。 您不能强迫该GC不收集它

软参考 ::与软参考大致相同。但是可以说,它比垃圾回收中的弱引用更牢固地容纳了对象。

如果垃圾收集器在第一个生命周期本身中收集了弱引用,它将在下一个垃圾收集周期中收集软引用。

强参考 ::与上述两种参考相反。他们不太喜欢收集垃圾(大多数情况下从不收集垃圾)。

您可以参考以下链接以获取更多信息:

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/Reference.html


3
我认为这是错误的-“如果垃圾收集器在第一个生命周期本身中收集弱引用,它将在下一个垃圾收集周期中收集软引用。” 不一定是这样,您如何确定它们连续出现在GC中?GC甚至可以在第二次运行和第三次运行中允许软引用的对象存在。没有相关的文档,如果有,请提及指定的链接。
Saurabh Patil 2014年

2
另外,您的答案有点模糊,看这句话(它或多或少都像弱引用一样)。但可以说,它比垃圾回收中的弱引用更牢固地容纳了对象。-他显然是在询问差异而不是相似之处,所有这些词使该话题变得更加混乱而不是清晰。
萨拉·帕蒂(Saurabh Patil),2014年

@SaurabhPatil-错过了您的评论。答案在这里。1.“他显然是在问区别而不是相似之处”-请参阅问题的描述(不是“仅”标题),“请给我一些建议,请给我一些示例进行描述”。2.“但是您可以说它保留了更多的对象...。”我认为SOF也可以选择否决并提供新的答案。
萨比亚2015年

14

文章可以超有助于了解强,软,弱,虚引用。


为了给您一个总结,

如果您对某个对象有很强的引用,则该对象将永远无法由GC(垃圾收集器)收集/回收。

如果您的参考文献薄弱对象(而没有强引用),则该对象将在下一个GC周期中由GC回收。

如果您仅具有对对象的软引用(没有强引用),则仅当JVM内存不足时,GC才会回收该对象。

我们创建对象的幻像引用,以跟踪该对象何时入队ReferenceQueue。一旦知道可以执行精细的终结处理。(这将使您免于意外地复现该对象,因为幻影引用不会给您提供引用对象)。我建议你阅读文章以获得深入详细地介绍这一点。


所以你可以说,强大的参考具有最终的力量(GC永远无法收集)

软引用比弱引用更强大(因为软引用可以逃避GC周期,直到JVM内存不足)

弱引用甚至没有软引用强大(因为它们无法逃脱任何GC周期,如果对象没有其他强引用,则将被回收)。


餐厅类比

  • 服务员-GC
  • 您-堆中的对象
  • 餐厅面积/空间-堆空间
  • 新客户-在餐厅要桌子的新对象

现在,如果您是一个强大的客户(类似于强大的参考),那么即使有新客户进来餐厅或发生的事情,您也永远不会离开桌子(堆上的内存区域)。服务员无权告诉您(甚至要求您)离开餐厅。

如果您是一位软顾客(类似于软顾客),那么如果有新顾客进来,餐厅的服务员将不会要求您离开桌子,除非没有其他空桌子来容纳新顾客。(换句话说,服务员只会在有新客户进场并且没有其他可供该新客户使用的桌子时才要求您离开桌子)

如果您是弱顾客(类似于弱顾客),那么服务员可以(在任何时间)要求您离开餐厅:P


10

4度参考- Strong, Weak, Soft, Phantom

强-是一种引用,使引用的对象不符合GC的条件。构建器类。例如-StringBuilder

弱-是可以用于GC的参考。

软-是一种引用,其对象可以使用GC,直到有可用的内存为止。最适合图像缓存。它将保持它们直到有可用的内存。

幻影-是一种引用,其对象直接可以用于GC。仅用于了解何时从内存中删除对象。

用途:

  1. 允许您确定何时从内存中完全删除对象。

  2. finalize()方法重载时,两个类的符合GC要求的对象可能无法及时发生GC。因此,幻影引用使他们有资格获得GC资格finalize()具有,这就是即使大部分堆都是垃圾时仍会出现OutOfMemoryErrors的原因。

弱引用是实现高速缓存模块的理想选择。


10

强引用

这些是我们每天编写的常规对象引用:

Employee emp = new Employee();

变量“ emp”拥有对Employee对象的强引用,并且通过任何强引用链均可访问的对象不符合垃圾回收的条件。通常,这就是您想要的,但并非总是如此。现在,假设我们要从集合或映射中的数据库中获取很多员工,并且需要定期对其进行大量处理,因此,为了保持性能,我们会将其保留在缓存中。

只要这很好,但现在我们需要不同的数据,就不需要那些Employee对象,并且除了缓存之外,其他任何地方都没有引用这些对象。是什么原因导致内存泄漏,因为这些对象未被使用,但仍不符合垃圾回收的条件,并且由于没有引用它们而无法从缓存中删除这些对象?因此,在这里我们要么需要手动清空整个缓存,这很繁琐,要么可以使用其他类型的引用,例如“弱引用”。

参考文献薄弱

弱引用不会将对象固定到内存中,如果未从其他引用中引用,则将在下一个GC周期中进行GC处理。我们可以使用Java提供的WeakReference类来创建上述类型的缓存,该缓存将不存储未从其他地方引用的对象。

WeakReference<Cache> cache = new WeakReference<Cache>(data);

要访问数据,您需要调用cache.get()。如果弱引用是垃圾回收,则此get调用可能返回null:必须检查返回的值以避免NPE。Java提供了使用弱引用的集合,例如,WeakHashMap类将键(而非值)存储为弱引用。如果键是GC,则该值也会自动从地图中删除。

由于弱引用也是对象,因此我们需要一种清理它们的方法(当它们所引用的对象经过GC处理时,它们将不再有用)。如果将ReferenceQueue传递给构造函数以获取弱引用,则垃圾收集器会在完成弱化或GC之前将弱引用附加到ReferenceQueue。您可以定期处理此队列并处理无效引用。

软参考

SoftReference就像WeakReference,但是不太可能被垃圾回收。垃圾回收器可根据内存需求酌情清除软引用。虚拟机保证在抛出OutOfMemoryError之前,将清除对所有可软访问对象的软引用。

幻影参考

幻象引用是所有引用类型中最弱的,对它们调用get将始终返回null。在完成对象之后,但在回收分配的内存之前,对对象进行幻像引用。与在完成对象之前将其排队的弱引用或很少使用GC的幻像引用相反。

那么它们有什么用呢?构造幻像引用时,必须始终传递ReferenceQueue。这表明您可以使用幻像引用来查看对象何时进行了GC处理。

嘿,因此,如果弱引用在被认为已完成但尚未进行GC时入队,则可以在终结器块中为该对象创建一个新的强引用,并防止该对象被GC处理。是的,可以,但是您可能不应该这样做。为了检查这种情况,除非每个对象仅通过幻像引用可访问,否则GC周期将至少发生两次。这就是为什么即使内存中包含大量垃圾也可能耗尽堆的原因。幻像引用可以防止这种情况。

您可以在我的文章Java中的引用类型(强,软,弱,幻影)上阅读更多内容。


您曾写道,如果不从其他参考书中删除弱的参考书,则会在下一个周期中对它进行GC处理...但是对于Stron的参考书,难道不应该发生同样的事情吗?如果无法以任何方式访问stron Refre,则将其清除...如果是,则区别又在哪里...?#confused
filemonczyk

1
如果从s1(强)和s2(强)中引用对象,则直到s1和s2都被取消引用,但如果从s1(弱)和s2中引用了对象,则该对象将不符合垃圾回收的条件(强),则仅当从s2取消引用对象时,该对象才有资格在下一个GC周期进行垃圾回收,因为s1是弱引用,并且如果对象除弱引用之外没有其他任何引用,则它有资格进行GC
Naresh Joshi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.