Java:强/弱/弱/幻像参考之间的区别

时间:2012-03-21 16:43:55

标签: java reference weak-references soft-references phantom-reference

我已阅读this article有关该主题的内容,但我并不理解。 在描述这些概念时,请给我一些建议和示例。

7 个答案:

答案 0 :(得分:126)

Java提供两种不同类型/类的参考对象。弱引用对象可以进一步分为 soft phantom 。让我们一点一点地走。

强参考对象

StringBuilder builder = new StringBuilder();

这是参考对象的默认类型/类,如果没有不同的指定:builder是一个强引用对象。这种引用使引用的对象不符合GC的条件。也就是说,只要一个对象被强引用对象的链引用,它就不能被垃圾收集。

弱参考对象

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

弱引用对象不是引用对象的默认类型/类,要使用它们应该像上面的示例中那样明确指定。这种引用使参考对象符合GC的条件。也就是说,如果内存中的StringBuilder对象唯一可达的引用实际上是弱引用,则允许GC垃圾收集StringBuilder对象。当内存中的对象只能由弱引用对象访问时,它将自动符合GC的条件。

弱点水平

可以使用两种不同级别的弱点: soft phantom

soft 参考对象基本上是一个弱的参考对象,它在内存中保留更多:通常,它会阻止GC循环,直到内存可用且不存在OutOfMemoryError的风险(在这种情况下,它可以删除)。

另一方面,幻像参考对象仅用于确切知道对象何时从内存中有效删除:通常它们用于修复怪异的终结()复活/复活行为,因为它们实际上并不返回对象本身,而只是帮助in keeping track of their memory presence

弱参考对象是实现缓存模块的理想选择。事实上,只要强引用链无法再访问对象/值,GC就可以实现一种自动驱逐。一个例子是WeakHashMap保留弱键。

答案 1 :(得分:71)

弱参考:

简单地说,弱引用是一个不足以强制对象保留在内存中的引用。弱引用允许您利用垃圾收集器为您确定可达性的能力,因此您不必自己完成。

软参考:

软引用与弱引用完全相同,只是它不太愿意丢弃它引用的对象。一个只能弱访问的对象(对它的最强引用是WeakReferences)将在下一个垃圾收集周期被丢弃,但是一个可以轻松到达的对象通常会暂停一段时间。

幽灵参考:

幻像引用与SoftReference或WeakReference完全不同。它对它的对象的抓握是如此脆弱,你甚至无法检索对象 - 它的get()方法总是返回null。这种引用的唯一用途是跟踪它何时被引入ReferenceQueue,因为那时你知道它指向的对象已经死了。

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

答案 2 :(得分:23)

SoftReferenceWeakReference之间的简单区别由Android Developer提供。

SoftReferenceWeakReference之间的差异是决定清除和排列参考的时间点:

  • SoftReference应该尽快清除并加入队列, 也就是说,万一VM存在内存不足的危险。

  • 一旦知道,WeakReference就可以被清除并入队 弱引用。

答案 3 :(得分:16)

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

弱引用 ::它的引用不足以强制对象保留在内存中。它的垃圾收集器突发奇想来收集垃圾收集对象。 您不能强制GC不收集

软参考 ::与弱引用或多或少相同。但是你可以说它比垃圾收集中的弱引用更强烈地保留了对象。

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

强引用 ::它与上述两种引用正好相反。 他们不太喜欢收集垃圾(大多数情况下他们从未被收集过。)

有关详细信息,请参阅以下链接:

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

答案 4 :(得分:10)

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

  

强 - 是一种引用,它不会引用引用的对象   有资格获得GC。建造者课程。例如 - StringBuilder

     

弱 - 是符合GC条件的参考。

     

Soft - 是一种引用,其对象符合GC条件,直到可以使用内存。最适合图像缓存。它将保留它们直到记忆可用。

     

Phantom - 是一种参考,其对象直接符合GC的条件。仅用于了解何时从内存中删除对象。

的用途:

  
      
  1. 允许您识别何时从内存中删除对象。

  2.   
  3. finalize()方法重载时,GC可能不会及时发生,因为这两个类的GC符合条件的对象。因此幻像引用使它们在finalize()之前符合GC的条件,这就是为什么即使大部分堆都是垃圾也可以获得OutOfMemoryErrors

  4.   

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

答案 5 :(得分:5)

article对于理解强,弱,弱和幻像引用非常有帮助。


为您提供一个摘要,

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

如果您仅对对象弱引用(没有强引用),则该对象将在下一个GC周期被GC回收。

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

我们为对象创建虚拟引用,以跟踪该对象何时进入ReferenceQueue的队列。一旦知道可以执行精细的终结处理。 (这将使您免于意外复活该对象,因为幻影引用不会给您提供引用对象)。建议您阅读this文章以获取有关此内容的详细信息。


所以您可以说,强引用具有终极威力(无法被GC收集)

软引用比弱引用功能强大(因为它们可以逃避GC周期,直到JVM内存耗尽)

弱引用比软引用功能更弱(因为它们无法排除任何GC周期,如果对象没有其他强引用,则将其回收)。


餐厅类比

  • 侍者-GC
  • 您-堆中的对象
  • 餐厅区域/空间-堆空间
  • 新客户-想要在餐厅中使用桌子的新对象

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

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

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

答案 6 :(得分:4)

强引用

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

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'd,则该值也将自动从地图中删除。

由于弱引用也是对象,我们需要一种方法来清理它们(当它们引用的对象已被GC化时,它们不再有用)。如果将ReferenceQueue传递给弱引用的构造函数,那么垃圾收集器会在它们最终化或GC之前将该弱引用附加到ReferenceQueue。您可以定期处理此队列并处理死引用。

软参考

SoftReference就像WeakReference,但它不太可能被垃圾收集。软件引用由垃圾收集器自行决定,以响应内存需求。虚拟机保证在发出OutOfMemoryError之前,所有对软可访问对象的软引用都将被清除。

幽灵参考

幻像引用是所有引用类型中最弱的,调用get on它们将始终返回null。一个对象在最终确定后被引用,但在它已分配的内存被回收之前,与在最终确定之前排队的弱引用相反,或者很少使用GC的幻影引用。

那么它们有用吗?构造幻像引用时,必须始终传入ReferenceQueue。这表示您可以使用幻像引用来查看对象何时进行GC。

嘿,所以如果弱引用在被认为是finalize但尚未GC的时候被排队,我们可以在终结器块中创建一个新的强引用对象,并阻止对象进行GC。是的,你可以,但你可能不应该这样做。要检查这种情况,每个对象的GC循环至少会发生两次,除非该对象只能通过幻像引用访问。这就是为什么即使内存中包含大量垃圾也可能会耗尽堆。幻影参考可以防止这种情况。

您可以在我的文章Types of References in Java(Strong, Soft, Weak, Phantom)上阅读更多内容。