Java:强/软/弱/幻影引用的区别

我读过这篇文章关于Java中不同类型的引用(强,软,弱,幻影),但我不是真的理解它。

这些引用类型之间的区别是什么,什么时候使用每种类型?

100215 次浏览

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

弱引用::它是一个不够强的引用,不能强制对象保留在内存中。它是垃圾收集器的奇思妙想来收集该对象进行垃圾收集。 你不能强迫GC不收集

软引用::它或多或少类似于弱引用。但是您可以说,它比垃圾收集中的弱引用更强地保存对象。

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

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

你可以参考下面的链接了解更多信息:

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/Reference.html < a href = " http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ref/Reference.html " > < / >

SoftReferenceWeakReference之间的简单区别由Android开发者提供。

SoftReferenceWeakReference之间的区别是决定清除引用并将其排队的时间点:

  • A SoftReference应该被清除并尽可能晚地加入队列, 即防止虚拟机存在内存不足的危险。李< / p > < / >

  • A WeakReference可以在已知的情况下被清除并加入队列 李weakly-referenced . < / p > < / >

弱参考:

简单地说,弱引用是指没有强到足以迫使对象保留在内存中的引用。弱引用允许您利用垃圾收集器的能力来确定您的可达性,因此您不必自己做这件事。

软参考:

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

幻影参考:

虚引用与软引用或弱引用是完全不同的。它对对象的控制是如此脆弱,以至于您甚至无法检索对象——它的get()方法总是返回null。这种引用的唯一用途是跟踪它何时进入ReferenceQueue队列,因为在这一点上,您知道它所指向的对象已经死亡。

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

Java提供了两种不同类型/类的引用对象: <强大的>强大的。弱引用对象可以进一步分为幻影

  • 强大的
  • <李>弱
    • 幻影
    • 李< / ul > < / >

    让我们逐点分析。

    强引用对象

    StringBuilder builder = new StringBuilder();
    

    这是默认类型/类的引用对象,如果没有不同的指定:builder是一个强引用对象。这种引用使得被引用的对象不适合GC。也就是说,当一个对象被强引用对象链引用时,它不能被垃圾收集。

    弱引用对象

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

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

    弱点的程度

    可以使用两种不同级别的弱点:幻影

    引用对象基本上是一个弱引用对象,它会在内存中保留更长时间:通常,它会抵抗GC循环,直到没有可用内存,并且存在OutOfMemoryError的风险(在这种情况下,它可以被删除)。

    另一方面,幻影引用对象仅在确切地知道对象何时已从内存中有效移除时有用:通常它们用于修复奇怪的finalize()复活/复活行为,因为它们实际上不返回对象本身,而只帮助追踪他们的记忆存在

    弱引用对象是实现缓存模块的理想对象。事实上,当强引用链不再访问对象/值时,可以允许GC清理内存区域,从而实现一种自动清除。一个例子是WeakHashMap保留弱键。

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

Strong -是一种引用,它使被引用的对象不是 有资格获得GC。构建器类。StringBuilder

Weak -是一个符合GC条件的引用。

Soft -是一种引用,其对象在内存可用之前都有资格进行GC。最适合图像缓存。它将保存它们,直到内存可用为止。

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

用途:

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

  2. finalize()方法重载时,对于这两个类中符合GC条件的对象,GC可能不会及时发生。因此,虚引用使它们在finalize()之前有资格进行GC,这就是为什么即使堆的大部分是垃圾,你也可以得到OutOfMemoryErrors

弱引用是实现缓存模块的理想方法。

强引用

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

Employee emp = new Employee();
变量“emp”保存了对Employee对象的强引用,通过任何强引用链可访问的对象都不符合垃圾收集的条件。 通常,这是你想要的,但并不总是如此。现在假设我们在一个集合或映射中从数据库中获取大量的员工,我们需要定期对他们进行大量的处理,所以为了保持性能,我们将他们保存在缓存中 到目前为止,这是很好的,但现在我们需要不同的数据,我们不需要那些雇员对象,这些不从任何地方引用,除了缓存。这导致了内存泄漏,因为这些对象没有被使用,但仍然不符合垃圾收集的条件,我们不能从缓存中删除这些对象,因为我们没有对它们的引用? 因此,在这里,我们要么需要手动清空整个缓存,这很乏味,要么我们可以使用其他类型的引用,例如弱引用

弱引用

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

WeakReference<Cache> cache = new WeakReference<Cache>(data);
要访问数据,需要调用cache.get()。如果弱引用被垃圾回收,这个get调用可能返回null:你必须检查返回值以避免npe。 Java提供了使用弱引用的集合,例如WeakHashMap类将键(而不是值)存储为弱引用。如果键被GC了,那么该值也会自动从映射中移除

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

软引用

软引用类似于弱引用,但它不太可能被垃圾收集。垃圾收集器根据内存需求自行清除软引用。虚拟机保证在抛出OutOfMemoryError错误之前,对软可达对象的所有软引用都将被清除。

幽灵的引用

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

那么它们有什么用处呢?当你构造一个虚引用时,你必须传递一个referencqueuue。这表明您可以使用幻影引用来查看对象何时被GC。

嘿,所以如果弱引用在被认为是最终确定的但还没有被垃圾收集时进入队列,我们可以在终结器块中创建一个新的对对象的强引用,并防止对象被垃圾收集。是的,你可以,但你可能不应该这样做。为了检查这种情况,GC循环将对每个对象至少进行两次,除非该对象只能通过幻影引用访问。这就是为什么即使内存中包含大量垃圾,也会耗尽堆的原因。幻影引用可以防止这种情况。

你可以阅读更多关于我的文章Java中的引用类型(强,软,弱,幻影)

这个文章对于理解强引用、软引用、弱引用和幻影引用非常有帮助。


总结一下,

如果你有一个对象的强引用,那么该对象永远不能被GC(垃圾收集器)收集/回收。

如果一个对象只有弱引用(没有强引用),那么该对象将在下一个GC循环中被GC回收。

如果你对一个对象只有软引用(没有强引用),那么只有当JVM内存耗尽时,这个对象才会被GC回收。

我们为对象创建幽灵的引用,以跟踪对象何时进入ReferenceQueue队列。一旦您知道可以执行细粒度终结。(这将避免意外地复活对象,因为phantom-reference不给你referrant)。我建议你阅读的文章来深入了解这方面的细节。


所以你可以说,强引用有最高权力(永远不能被GC收集)

软引用比弱引用是强大的(因为它们可以逃避GC循环,直到JVM耗尽内存)

弱引用比软引用是更不强大(因为它们不能逃脱任何GC循环,并且如果对象没有其他强引用将被回收)。


餐厅的类比

  • 服务员- GC
  • 堆中的对象
  • 餐厅区域/空间-堆空间
  • 新客户-在餐厅想要桌子的新对象

现在如果你是强大的客户(类似于强引用),那么即使餐馆来了一个新顾客或发生了什么事情,你也不会离开你的表(堆上的内存区域)。服务员没有权利告诉你(甚至要求你)离开餐厅。

如果你是软客户(类似于软引用),那么如果餐厅来了一位新顾客,服务员不会让你离开桌子,除非没有其他空桌子来容纳这位新顾客。(换句话说,只有当一个新顾客进来,并且没有其他的桌子给这个新顾客时,服务员才会叫你离开桌子)

如果你是一个薄弱的客户(类似于弱引用),那么服务员,在他的意愿,可以(在任何时候)要求你离开餐厅:P