When to use Weak and Phantom references in Java
我读了很多文章,但我不明白——在实践中,我需要在哪里使用弱引用和虚引用?软引用——据我所知,是缓存的好选择。但软弱和幻影,我不知道什么时候用。请提供我们需要使用的实际任务的示例。
- 你不需要使用幻影参考。这些是内部使用的。你在使用软引用的地方使用弱引用,除非它们的寿命更短。当弱引用只有在另一个对象也有引用时才有意义时,可以使用它们。例如听众。
您可以对缓存使用弱引用,就像您所说的软引用一样。
幻影参考有什么好处?我只知道它们有两个严重的情况:第一,它们允许您确切地确定从内存中删除对象的时间。事实上,它们是唯一确定这一点的方法。这通常没有那么有用,但在某些非常具体的情况下(如操作大型图像)可能会很有用:如果您确定应该对图像进行垃圾收集,则可以等到它实际存在时再尝试加载下一个图像,从而降低可怕的内存不足的可能性。
其次,phantomreferences避免了终结的一个基本问题:finalize()方法可以通过创建对对象的新的强引用来"复活"对象。你说呢?好吧,问题在于,现在必须确定重写finalize()的对象在至少两个单独的垃圾收集周期内是垃圾,以便进行收集。当第一个循环确定它是垃圾时,它就可以进行终结。由于对象在终结过程中"复活"的可能性(很小,但很不幸是真实的),垃圾收集器必须在实际删除对象之前再次运行。而且,由于可能没有及时完成,因此在对象等待完成时,可能会发生任意数量的垃圾收集周期。这可能意味着实际清理垃圾对象时会有严重的延迟,这也是为什么即使堆中的大部分是垃圾,也可以从内存错误中得到好处的原因。
有关详细信息,请参阅本页:http://weblogs.java.net/blog/2006/05/04/understanding-weak-references
- 弱引用对于缓存是绝对无用的。
- 一个可终结的对象被复活的概率并不是"很小"——它是100%;一个可终结的对象如果没有finalize方法的存在,它将在它的终结器开始运行时被放在堆栈上,对它有很强的引用。在该引用(以及所有其他根引用)停止存在之前,无法删除该对象。
- 根据oome javadoc Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.的说法,大图像是否在内存中并不重要,因为如果是的话,它会在失败之前将其扔掉。否则,您应该知道您是否持有对它的任何剩余引用。
基本上,当您想将一些额外的数据与源代码不受您控制的对象相关联时,您将使用弱引用。通过使用弱引用,可以将元对象的生命周期与主对象的生命周期结合起来。
幻影引用的主要用例是实现您自己的终结器线程,而不存在与默认机制相关联的危险,该机制强制引用终结代码所访问的假定不可访问的对象。
软引用主要用于缓存,但正如本文另一篇文章所述,软引用在实践中会产生灾难性的影响,从而破坏了缓存的关键点。一个主要的GC(将清除你的软引用的GC)通常不会发生,直到你的应用程序性能压力上升。这是您最需要缓存的时间,也是您最可能同时丢失缓存的时间–。
- 根据行动计划,他想知道什么时候使用虚参考和弱参考。……你的回答并不能完全回答他原来的问题。
- 不,你是在歪曲问题,那就是什么时候使用弱引用和虚引用。它不是关于如何在它们之间进行选择,而是关于何时使用它们中的任何一个。所以,即使这个答案不涉及幻影参考(在你评论的时候,它现在就处理了),它所说的一切都是关于主题和正确的。
- 我同意,新的答案很好地涵盖了这个话题。
我认为这篇文章很好地回答了你的问题。
Java中的软引用和弱引用有什么区别?
基本上,软引用比弱引用略强。弱引用将在下一个GC循环中被丢弃,而软引用将保留在内存中,直到内存有压力,并且JVM希望尽可能多地回收。
您应该考虑到您的程序仍然有效的引用对您的程序有多重要。对于一些非常便宜的东西,我倾向于创建一个weakreference,但是如果它是一个来自db的值,那么您可能倾向于软引用,因为您不想重新运行查询,除非您真的需要。
- 谢谢您。但我理解这些引用类型之间的区别。我不明白在什么具体任务中可以应用它们。
- 我添加了我对何时使用弱引用与软引用的看法
这篇文章对这个问题有一个很好的答案。
在垃圾收集所有weakreference对象之前,不会收集SoftReference对象。
因此,将不太重要的对象放在weakreference对象中,并使用软引用对象来保存更重要的对象。
鉴于这些事实,在垃圾收集方面,您应该根据需要使用好的引用对象。首先收集weakreference,然后收集softreference,最后收集phantomreference。
文件上说:
- 软引用用于实现内存敏感的缓存
- 弱引用用于实现规范化映射,这些映射不会阻止其键(或值)被回收。
顺便说一下,在某些情况下,出于缓存的目的,最好使用weakreference而不是softreference,因为缓存在内存中可能很重,因此需要清理。
对于phantomreference,使用是不同的。它们是1〔0〕。
本文将详细介绍什么可以使用幻象引用。
- 关于弱引用和软引用,你是非常正确的。关于幻象引用,你错了。phantomreferences仅可用于替代finalize方法(即资源清理)。它们与缓存或对象何时得到gc'ed无关。
- @jtahlborn首先,我从来没有说过phantomreferences用于缓存(我指的是与op中所述内容相关的weakreference)。然后我知道它是一个替换FialAlIZE(),但是对于GC顺序,我在Java PrF调优中读取它,并且这个链接似乎说了同样的事情:DOCS.Oracle .COM/JavaSe/ 7 /DOCS/API/Java/Lang/Ref//Helip;
- 你的第二句到最后一句似乎意味着你将根据收集的时间在不同类型之间进行选择。我的观点是,您使用的幻象引用与弱/软引用完全不同,所以这句话毫无意义(是的,您对收集顺序是正确的,这不是我的观点)。
- 你弄错了两件事。1。不能使用幻影引用来到达引用。2。弱引用对于缓存是无用的。他们一点也不拖延公投的举行。这样的缓存将在第一个次要GC时被清除。
- @我明白,我重写了它。
- @马尔科托普尼克.Weak refs are useless for caching. They don't delay the GCing of their referents at all。我不是说,我说弱参考延迟软参考的GC,我不是说他们的参考。我不同意你的观点,弱的refs对于缓存来说并不是无用的,ofc它们将gc,但这就是我想的目标,缓存太大了,所以需要首先回收。
- 弱引用不会延迟任何内容——一旦引用对象没有"正常"引用(不可强烈访问),它们就会被清除。这就是它们作为缓存失败的原因——对象将进入年轻一代,并在几秒钟内被清除,而自由堆仍有充足的供应。
- @Markotopolinik Weak refs ... get cleared as soon as there is no"normal" reference我知道当它们被清除时,我要说的是,如果仍然存在弱引用,那么SOFT不是GC!而且,对于缓存,我读到在Java PrF调谐中,我从来没有尝试过自己,所以你可能是对的。作者写道,这句话是开放式讨论;)。他给出的结论是根据重建对象的成本选择适当的参考。
- 另一种情况是:软的比弱的强,所以如果一个物体是软的,弱的参考将不会被清除。这证实了我的说法,你需要一个软引用来缓存。至于使用弱缓存,考虑到这种缓存的寿命有多短,仅维护这种缓存的开销很快就会淹没它可能带来的任何好处。
- @Markotopolnik是的,这正是我所说的,如果仍然存在弱引用,那么软引用更强,所以它们不是GC。弱引用不太重要,所以在软引用之前收集。我说弱引用延迟了软引用的GC,因为它们必须在GC可以清除软引用之前收集。
- 但我不是这么说的:软裁判的生活绝不会受到弱裁判的(非)存在的影响!一个软弱的裁判无论有没有软弱的裁判,都能活下去——这并不重要。不是这样的。
- 从Java性能调整ED2:WeakReferences and SoftReferences differ essentially in the order in which the GC clears them. Simplistically, the GC does not clear SoftReference objets until all WeakReferences have been cleared.@
- 你引用的是对事物的简单描述,读的比写的要多。引用完全符合我的陈述和你的推论,weakrefs以某种方式延迟了SoftRefs的收集,这是武断的——也是错误的。
- 想想这句话吧:你只有在十几岁的时候才会长大。青少年会推迟你的成年吗?
- @不幸的是,作者没有对这句话做更多的阐述。""delay"可能不是英语中的词,对不起,有时我用错了词…我想这句话的意思是,你必须等到"青少年年"结束后再"成年"。顺便说一句,谢谢分享你的知识,让事情更清楚。
- 最后一句话:关于哪个ref更适合缓存的讨论大多是空谈,因为在实际的项目中,您永远不会尝试从头开始实现缓存:您将使用一个经过战斗验证的实现,如ehcache。好的缓存充满了微妙之处,你只是不想重塑自己,堆上对象的生命周期决不是专门提供好的缓存性能。现代缓存甚至不使用堆进行缓存,而是使用堆外存储,因为它们希望完全控制缓存对象的生命周期。