据我所知,弱引用受到垃圾收集器的支配,我们不能保证弱引用会存在。我看不出需要弱参考,但确定应该有理由。
答案 0 :(得分:16)
使用弱哈希映射实际上通常是一个坏主意。一方面容易出错,但更糟糕的是它通常用于实现某种缓存。
这意味着以下内容:您的程序在一段时间内运行良好且性能良好,在压力下我们分配越来越多的内存(更多的请求=更多的内存压力=可能更多的缓存条目),然后导致GC。
现在,当您的系统处于高压力状态时,您不仅会获得GC,而且还会丢失整个缓存,就在您最需要它的时候。这个问题并不好玩,所以你至少必须使用一个合理大小的硬引用LRU缓存来缓解这个问题 - 你仍然可以使用weakrefs,但仅作为额外的帮助。
我看过不止一个项目被“虫子”击中..
答案 1 :(得分:6)
我见过的弱引用最“明确无误”的使用是Guava的Striped
,它确实锁定了条带化。基本上,如果没有线程当前持有对锁变量的引用,那么没有理由保持锁定,是吗?那个锁可能在过去曾被使用过,但现在没有必要。
如果我必须在你使用时给出一个规则,我会说当你可能将来使用某些东西时,软引用更可取,但是如果你确实需要它可以重新计算它;当您可以确定在引用内存不足后永远不需要该值时,弱引用尤其可取。 (例如,如果对映射键类型使用特定equals(Object)
实现的默认引用相等性,并且该对象在其他任何地方停止引用,那么您可以确定该条目将永远不会再被引用。
答案 2 :(得分:4)
我使用弱引用的主要原因是间接地通过WeakHashMap。
您可能希望在Map中存储对象集合(作为缓存或出于任何其他原因),但是只要Map存在,就不希望它们在内存中,特别是如果对象是相对的大。
通过使用WeakHashMap,您可以确保Map中的引用不是将对象保留在内存中的唯一方法,因为如果不存在其他引用,它将被垃圾收集。
答案 3 :(得分:3)
假设您需要保留一些信息,只要引用了一个对象,但您不知道它什么时候会消失,您可以使用弱引用来跟踪信息。
答案 4 :(得分:2)
是的,它有很好的影响力。
上面的“小部件序列号”问题示例,最简单的方法是使用内置的
WeakHashMap
类。WeakHashMap
与HashMap
完全相同,只是使用弱引用引用键(而不是值!)。如果WeakHashMap
密钥变为垃圾,则会自动删除其条目。这样可以避免我所描述的陷阱,除了从HashMap
切换到WeakHashMap
之外,不需要进行任何更改。如果您遵循通过Map
界面引用地图的标准惯例,则其他代码甚至不需要知道更改。
答案 5 :(得分:1)
JVM平台需要弱引用对象以确保防止内存泄漏的方法。
正如Java开发人员应该知道的那样,Java可能会泄漏,超出预期。在不再使用Object的情况下,这种说法尤其正确,但某些集合仍强烈反对该实例:一个非常简单但经常出现的内存泄漏示例,实际上在存在强引用之前,内存区域不会被释放。
在上面的例子中,集合中的弱引用对象确保:没有强引用链,但只有弱链,实例可以作为garbace可收集。
在我看来,Java平台提供的所有功能在某种程度上都是有用的:非常熟练的程序员可以驱动Java快速可靠,因为C ++编写了非常高质量的代码。
答案 6 :(得分:0)
需要制作Java garbage collection deterministic。 (从略带讽刺的观点来看,有一些道理)。
答案 7 :(得分:0)
WeakReference
很好,当您希望让某个对象前往垃圾回收而不必从其他持有引用的对象中正常删除自己时。
在publish-subscribe或事件总线之类的场景中,保留了对订阅对象的引用的集合。这些参考应该是弱的,以便订户可以方便地超出范围而不必费心取消订阅。在应用程序中的所有其他位置发布了有力的参考之后,订阅者才可以“消失”。此时,订阅列表或事件总线不再需要挂接到订阅者。 WeakReference
的使用允许对象继续进入遗忘状态。
该订阅对象可能已被订阅,而没有其他知识,该订阅对象已由其他第三方对象提交给发布订阅或事件总线。在订户生命周期的后期协调取消预订的呼叫可能非常麻烦。因此,在不正式取消订阅的情况下让订阅者淡出可以大大简化您的代码,并且可以避免难以解决的错误(如果取消订阅的协调失败)。
这是一组线程安全的弱引用的示例,如this Answer和this Answer所示。
this.subscribersSet =
Collections.synchronizedSet(
Collections.newSetFromMap(
new WeakHashMap <>()
)
);
请注意,直到之后垃圾收集实际执行之后,集合中的条目才被真正删除,如上面链接的Answer中所讨论的。当作为垃圾收集的候选对象存在时(任何地方都没有剩余的强引用),该项目仍保留在集合中。