有没有人研究过创建和垃圾收集 Java WeakReference对象所涉及的运行时成本?多线程应用程序是否存在任何性能问题(例如争用)?
编辑:显然,实际答案将取决于 JVM,但也欢迎一般观察。
编辑2:如果有人对性能进行了一些基准测试,或者可以指出一些基准测试结果,那将是理想的。(对不起,赏金已过期......)
有没有人研究过创建和垃圾收集 Java WeakReference对象所涉及的运行时成本?多线程应用程序是否存在任何性能问题(例如争用)?
编辑:显然,实际答案将取决于 JVM,但也欢迎一般观察。
编辑2:如果有人对性能进行了一些基准测试,或者可以指出一些基准测试结果,那将是理想的。(对不起,赏金已过期......)
WeakReferences 对 CMS 垃圾收集器有负面影响。据我所知,从我们服务器的行为来看,它会影响并行备注阶段时间。在此阶段,所有应用程序线程都将停止,因此这是非常不可取的事情。所以你需要小心 WeakReferences。
我曾经实现过一个 Java 垃圾收集器,所以我能够完成的只是一个(弱 :) 可能的下限。
在我的实现中,在垃圾收集期间访问每个弱引用时,都会有少量恒定的额外开销。
所以结果是:我不会担心它,这不是一个大问题,除非你使用无数的弱引用。
最重要的是,成本与存在的弱引用数量成正比,而不是与整个堆的大小成正比。
然而,这并不是说支持弱引用的垃圾收集器与不支持弱引用的垃圾收集器一样快。这里假设的问题是,鉴于 Java 支持弱引用,使用它们的增量成本是多少?
我的是一个简单的“停止世界”标记/清扫垃圾收集器。在垃圾回收期间,它会为每个对象确定该对象是否处于活动状态,并LIVE
在对象头中设置一个位。然后它通过并释放所有非活动对象。
要处理弱引用,您只需添加以下内容:
LIVE
(即,它们不会导致LIVE
设置被引用对象上的位)。LIVE
,并且是a WeakReference
,那么检查它弱引用的对象,如果不是LIVE
,清除引用。这种逻辑的微小变化适用于软引用和幻像引用。
如果你真的很好奇,实现就在这里。
如果它是按需重建的,例如在 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) GC 清除弱引用,因此缓存也被清除
3)app继续,调用getSomethingExpensiveToFind()等很多方法并重建缓存
4) 应用程序再次内存不足
5) GC 清除磨损引用,清除缓存
6)app继续,调用getSomethingExpensiveToFind()等很多方法,再次重建缓存
7)等等……
我遇到了这样的问题 - 该应用程序经常被 GC 中断,它完全破坏了缓存的全部意义。
换句话说,如果管理不当,弱引用会减慢您的应用程序。