Java中使用弱引用的成本

48

有没有人研究过创建和垃圾回收Java WeakReference对象所涉及的运行时成本?对于多线程应用程序,是否存在任何性能问题(例如争用)?

编辑:显然,实际答案将取决于JVM,但也欢迎一般性的观察。

编辑2:如果有人对性能进行了基准测试,或者可以指向一些基准测试结果,那就太好了。(抱歉,但悬赏已经过期了...)


显然这取决于JDK的实现,Sun vs IBM vs JRockit等。 - David Plumpton
4
在每次垃圾回收时,都必须构建一个活动引用对象列表,并且必须适当地处理每个引用,这会为每次回收增加一些与引用相关的开销,无论此时是否正在收集引用对象。 引用对象本身也会受到垃圾回收的影响,在引用对象被回收而尚未回收引用对象时,引用对象不会被排队。 - assylias
3个回答

13

弱引用会对CMS垃圾回收器产生负面影响。就我们服务器的行为来看,它会影响并行标记阶段的时间。在此阶段中,所有应用程序线程都会停止运行,因此这是一件极其不可取的事情。因此,您需要小心处理弱引用。


抱歉,我现在正在尝试弄清楚Sun论坛上这种行为的原因 :) - Vitaly
2
Vitaly,你现在有更多相关信息吗?如果你在Sun论坛上找到了一些信息,能否发一个链接?谢谢! - Owen
它们会产生什么影响呢,显然会有一些成本,因为垃圾收集需要特别处理弱引用等。 - mP.

8
我曾经实现过Java垃圾收集器,因此我能够实现的是可能性的一个弱下限。
在我的实现中,每个弱引用在垃圾回收期间被访问时都会有一个小的常量额外开销。
所以总的来说:我不会担心它,除非你正在使用大量的弱引用,否则这不是一个大问题。
最重要的是,成本与存在的弱引用数量成比例,而不是整个堆的大小。
然而,这并不意味着支持弱引用的垃圾收集器将像不支持弱引用的垃圾收集器一样快。假设问题是,既然Java支持弱引用,那么使用它们的增量成本是多少?
我的垃圾收集器是一个简单的“停止世界”标记/清除垃圾收集器。在垃圾收集期间,它确定每个对象是否存活,并在对象头中设置一个“LIVE”位。然后它遍历并释放所有非存活对象。
要处理弱引用,只需添加以下内容:
  • 当设置LIVE位时,忽略弱引用(即它们不会导致所引用的对象的LIVE位被设置)。
  • 在扫描步骤期间,添加一个特殊的检查如下:如果您正在访问的对象是LIVE,并且它是一个WeakReference,则检查它弱引用的对象,如果该对象不是LIVE,则清除引用。

这个逻辑的小变化也适用于软引用和虚引用。

如果您真的很好奇,实现在这里


1
这非常有趣。(我认为HotSpot实现方式不同。)当finalize方法重新链接引用对象的情况如何处理?那不需要触发(部分)重新标记吗? - Stephen C
我百分之百确定HotSpot的实现不仅不同,而且大大更为复杂 :) 关于finalize,那只是非LIVE对象的额外步骤。它应该真正地说“它会遍历并将所有非LIVE对象加入到finalization队列中”,而不是“它会遍历并释放所有非LIVE对象”。 - Archie
关于终结,您必须在对象头中设置一个位来指示是否已调用finalize(),以便不会重复执行。因此,如果未设置该位,则实际上非“LIVE”对象将被排队进行终结,如果设置了该位,则立即释放。 - Archie

3

如果应用程序是按需重建的,例如在getter中,使用弱引用进行缓存可能会显着减慢应用程序的运行速度:

public Object getSomethingExpensiveToFind() {
    if(cache.contains(EXPENSIVE_OBJ_KEY)) {
        return cache.get(EXPENSIVE_OBJ_KEY);
    }

    Object sth = obtainSomethingExpensiveToFind(); // computationally expensive
    cache.put(EXPENSIVE_OBJ_KEY, sth);
    return sth;
} 

想象以下情况:
1) 应用程序已经快没有足够的内存了;
2) 垃圾回收清理了弱引用,因此缓存也被清除;
3) 应用程序继续运行,调用了许多 getSomethingExpensiveToFind() 等方法,并重新构建了缓存;
4) 应用程序再次占用了大量内存;
5) 垃圾回收清理了弱引用,又一次清除了缓存;
6) 应用程序继续运行,调用了许多 getSomethingExpensiveToFind() 等方法,并再次重建了缓存;
7) 以此类推...
我遇到了这样的问题 - 应用程序经常被 GC 中断,完全打乱了缓存的整个意义。
换句话说,如果管理不当,弱引用会减慢应用程序的速度。

1
这并没有回答我所问的问题。你基本上是在说不明智地使用弱引用可能会对性能产生负面影响...因为对象缓存竞争。但问题是关于弱引用本身的开销。(理想情况下,我希望得到一个给出这些开销实际测量值的答案,但我也可以接受一个权威的解释,说明它们是如何产生的。) - Stephen C
那么你应该具体询问度量标准基准测试 - mantrid
我看到了。在奖金通知里。你看过了吗?但无论如何,你的回答显然与所提问的问题不相关。 - Stephen C
这仍然是一个有用的观察,与讨论并不无关。 - Will
@Will - 这不是一个讨论论坛,而是一个问答网站。如果我想发起讨论,我会在另一个网站上提问。如果我想问是否使用引用是一件好事...我会问一个不同的问题。 - Stephen C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接