【问题标题】:Cost of using weak references in Java在 Java 中使用弱引用的成本
【发布时间】:2009-08-09 03:27:05
【问题描述】:

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

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

编辑 2:如果有人对性能进行了一些基准测试,或者可以指出一些基准测试结果,那将是理想的。 (抱歉,赏金已过期……)

【问题讨论】:

  • 显然这将取决于 JDK 实现,Sun vs IBM vs JRockit 等。
  • Goetz 的一篇文章中的回答开始:在每次垃圾回收时,必须构造一个活动引用对象列表,并且必须适当处理每个引用,这增加了一些- 每次收集的引用开销,无论当时是否正在收集所指对象。引用对象本身会受到垃圾回收的影响,并且可以在所指对象之前被回收,在这种情况下它们不会入队。

标签: java garbage-collection weak-references


【解决方案1】:

弱引用对 CMS 垃圾收集器有负面影响。据我所知,从我们服务器的行为来看,它会影响并行备注阶段时间。在此阶段,所有应用程序线程都将停止,因此这是非常不可取的事情。所以你需要小心 WeakReferences。

【讨论】:

  • 对此很抱歉,但我现在正试图找出 Sun 论坛上出现此类行为的原因 :)
  • 维塔利,你现在还有这个吗?如果您在 Sun 论坛上找到了一些信息,您能否发布一个链接?谢谢!
  • 它们有什么样的影响,显然是有代价的,因为 gc 需要特殊情况下的弱引用等。
【解决方案2】:

我曾经实现过一个 Java 垃圾收集器,所以我能够完成的只是一个(弱 :) 可能的下限。

在我的实现中,在垃圾回收期间访问每个弱引用时,都会产生少量恒定的额外开销。

所以结果是:我不会担心,除非你使用无数弱引用,否则这不是什么大问题。

最重要的是,成本与存在的弱引用数量成正比,而不是与整个堆的大小成正比。

但是,这并不是说支持弱引用的垃圾收集器与不支持弱引用的垃圾收集器一样快。这里假设的问题是,鉴于 Java 支持弱引用,使用它们的增量成本是多少?

我的是一个简单的“停止世界”标记/清除垃圾收集器。在垃圾回收期间,它会为每个对象确定该对象是否处于活动状态,并在对象头中设置一个LIVE 位。然后它会遍历并释放所有非活动对象。

要处理弱引用,您只需添加以下内容:

  • 设置LIVE 位时忽略弱引用(即,它们不会导致设置被引用对象上的LIVE 位)。
  • 在sweep步骤中,添加一个特殊的检查如下:如果你访问的对象是LIVE,并且是WeakReference,那么检查它弱引用的对象,如果那个对象不是@ 987654327@,清除引用。

此逻辑的小变化适用于软引用和幻像引用。

如果你真的很好奇,实现是here

【讨论】:

  • 这很有趣。 (我认为 HotSpot 的实现是不同的。)你如何处理 finalize 方法重新链接引用对象的情况?那不需要触发(部分)重新标记吗?
  • 我 100% 确定 HotSpot 的实现不仅不同,而且更加复杂 :) Re: finalize,这只是非 LIVE 对象的额外步骤。而不是“它通过并释放所有非活动对象”它应该真正说“它通过并入队以完成所有非活动对象”。
  • Re: finalization,你必须在对象头中设置一个位来指示finalize()是否被调用,所以你不要按要求做两次。所以实际上非LIVE 对象如果未设置则排队等待最终确定,如果设置了该位,则立即释放。
【解决方案3】:

使用弱引用缓存可能会显着减慢您的应用,如果它是按需重建的,例如在吸气剂中:

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) GC 清理弱引用,因此缓存也被清除

3) 应用继续,调用getSomethingExpensiveToFind()等很多方法并重建缓存

4) 应用再次出现内存不足

5) GC 清除磨损引用,清除缓存

6) 应用继续,调用getSomethingExpensiveToFind()等方法,再次重建缓存

7) 等等……

我遇到了这样的问题 - 应用程序经常被 GC 中断,它完全破坏了缓存的全部意义。

换句话说,如果管理不当,弱引用会减慢您的应用程序。

【讨论】:

  • 这没有回答我提出的问题。您基本上是在说不明智地使用弱引用可能对性能不利……由于对象缓存抖动。但问题是关于弱引用本身的开销。 (理想情况下,我希望得到一个答案,对这些间接费用进行一些实际测量,但我也会接受对它们是如何产生的权威解释。)
  • 那么您应该专门询问 metricsbenchmarks
  • 我做到了。在奖金通知。你读了吗?但无论如何,您的答案显然与所问的问题无关。
  • 这仍然是一个有用的观察,并且与讨论无关。
  • @Will - 这不是一个讨论论坛。这是一个问答网站。如果我想发起讨论,我会在不同的网站上提问。如果我想问使用引用是否是一件好事......我会问一个不同的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-27
  • 1970-01-01
相关资源
最近更新 更多