【问题标题】:Java: difference between strong/soft/weak/phantom referenceJava:强/软/弱/幻引用之间的区别
【发布时间】:2012-04-06 05:38:05
【问题描述】:

我读过 this article 关于 Java 中不同类型的引用(强、软、弱、幻),但我不太了解。

这些引用类型有什么区别,每种类型什么时候使用?

【问题讨论】:

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


【解决方案1】:

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

弱引用 :: 它的引用强度不足以强制对象保留在内存中。 垃圾收集器的奇思妙想来收集该对象以进行垃圾收集。 您不能强制该 GC 不收集它

软引用 :: 和弱引用差不多。但是你可以说它比垃圾回收中的弱引用更强烈地持有对象。

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

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

您可以参考以下链接了解更多信息:

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

【讨论】:

  • 我认为这是错误的-“如果垃圾收集器在第一个生命周期本身收集弱引用,它将在下一个垃圾收集周期收集软引用。”不一定是这样,你怎么能确定它们在连续运行的 GC 中发生? GC 甚至可以允许软引用对象在第 2 次运行和第 3 次运行中仍然存在。没有它的文档,如果有,请提及指定的链接。
  • 另外,你的回答有点含糊,看这句话'它或多或少像weak reference一样。但你可以说它比垃圾收集的弱引用更强烈地持有对象。 - 他显然是在问差异而不是相似之处,所有这些词都给主题带来了更多的混乱而不是清晰。
  • @SaurabhPatil -- 错过了您的评论。这是答案。 1.“他明确问的是区别而不是相似之处”——参考问题的描述(不是“只”标题)“请给我一些建议,请给我一些例子来描述”。 2.“但你可以说它对物体的把握更大……”我认为 SOF 提供了一个选项来拒绝投票并给出新的答案。
【解决方案2】:

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

SoftReferenceWeakReference 之间的区别在于决定清除引用并将其加入队列的时间点:

  • SoftReference 应尽可能晚地被清除和排队, 也就是说,以防虚拟机面临内存不足的危险。

  • A WeakReference 可能会在已知的情况下立即被清除和排队 弱引用。

【讨论】:

    【解决方案3】:

    弱参考:

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

    软参考:

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

    幻影参考:

    幻像引用与 SoftReference 或 WeakReference 完全不同。它对其对象的控制非常脆弱,以至于您甚至无法检索该对象——它的 get() 方法总是返回 null。这种引用的唯一用途是跟踪它何时进入 ReferenceQueue,因为此时您知道它指向的对象已死。

    这段文字摘自:https://weblogs.java.net/blog/2006/05/04/understanding-weak-references

    【讨论】:

    • 虽然此答案中的所有内容看起来都正确,但在我看来,链接网页上可能存在错误。 Javadoc for package java.lang.ref 和 PhantomReference 建议一个对象在它不再“幻影可达”之后才会被垃圾收集,这意味着(与 SoftReference 不同)PhantomReference 必须在它引用的对象可以被垃圾收集之前出队。 .并且它被排队并不表示相关的内存已被释放。
    • 郑重声明,我宁愿生活在一个博客文章正确的世界里。
    • @TheodoreMurdock javadoc 是正确的。幻影引用根本不会妨碍垃圾收集。一旦对象入队,即使终结器也无法保存它,因为终结器已经运行。它已经死了,但还没有消失。
    • @Leliel 实际上,幻影引用确实实际上会在入队后阻碍垃圾收集......我最近意识到这一点,当时一个错误导致清理线程提前退出。幻像引用的存在足以确保 每个 幻像引用的对象都保留在我的堆转储中,无法收集...如果您无法处理队列,或者无法使幻像引用符合条件对于 gc 在处理队列时(并且不 clear() 幻像引用),那么您的内存泄漏将包括幻像引用和被引用的对象。
    • "与软引用和弱引用不同,幻像引用在入队时不会被垃圾收集器自动清除。通过幻像引用可访问的对象将保持不变,直到所有此类引用都被清除或自身变为遥不可及。”来源:Java8 API Docs PhantomReference
    【解决方案4】:

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

      • 幻影

    让我们逐点进行。

    强引用对象

    StringBuilder builder = new StringBuilder();
    

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

    弱引用对象

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

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

    弱点程度

    可以列出两种不同级别的弱点:softphantom

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

    另一方面,phantom 引用对象仅在准确了解对象何时从内存中有效删除时有用:通常它们用于修复 奇怪的 finalize() 复活/复活行为,因为它们实际上并不返回对象本身,而只是帮助in keeping track of their memory presence

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

    【讨论】:

    • 添加到 Q:strongRef --&gt; weakRef --&gt; objA。现在,objA 是否会被 GC,因为它有来自 strongRef 的间接引用。
    【解决方案5】:

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

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

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

    Soft - 是一种引用,其对象在内存可用之前符合 GC 条件。最适合图像缓存。它将保持它们直到内存可用。

    Phantom - 是一种引用,其对象直接符合 GC 条件。仅用于知道对象何时从内存中删除。

    用途:

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

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

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

    【讨论】:

      【解决方案6】:

      强引用

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

      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 类将键(而不是值)存储为弱引用。如果 key 被 GC 了,那么 value 也会自动从 map 中删除。

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

      软参考

      SoftReference 类似于 WeakReference,但它不太可能被垃圾回收。垃圾收集器根据内存需求自行决定清除软引用。虚拟机保证在抛出 OutOfMemoryError 之前清除所有对软可访问对象的软引用。

      幻影参考

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

      那么它们有什么用呢?当你构造一个幻像引用时,你必须总是传入一个 ReferenceQueue。这表明您可以使用幻像引用来查看您的对象何时被 GC。

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

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

      【讨论】:

      • 您写道,如果没有从其他引用中引用,弱引用将在下一个周期中被 GC'ed ......但是对于强引用不应该发生同样的事情吗?如果没有以任何方式访问强参考然后被清除......那么如果是这样,那么差异又在哪里......? #困惑
      • 如果一个对象被 s1 (strong) 和 s2 (strong) 引用,那么在 s1 和 s2 都被取消引用之前,该对象将不符合垃圾回收条件,但如果该对象被引用从 s1 (weak) 和 s2 (strong) 然后对象只有在从 s2 取消引用时才有资格在下一个 GC 周期进行垃圾回收,因为 s1 是一个弱引用并且如果对象除了弱引用之外没有任何其他引用它有资格获得 GC
      【解决方案7】:

      这个article 对理解强引用、软引用、弱引用和虚引用非常有帮助。


      给你一个总结,

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

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

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

      我们为对象创建幻像引用,以跟踪对象何时进入ReferenceQueue。一旦你知道你可以执行细粒度的终结。 (这将使您免于意外复活该对象,因为幻像引用不给您引用者)。我建议您阅读 this 文章以深入了解此内容。


      所以你可以这么说,强引用具有终极力量(永远不能被 GC 收集)

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

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


      餐厅类比

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

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

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

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

      【讨论】:

      • 该死,现在我想听一个以“软引用来到酒吧...”开头的故事
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-16
      • 2013-07-06
      • 1970-01-01
      相关资源
      最近更新 更多