我知道弱引用受垃圾收集器的支配,我们不能保证弱引用会存在。我看不出需要弱参考,但肯定应该有原因。
- 为什么我们需要在 java 中进行弱引用?
- java中弱引用的实际(一些)用途是什么?如果您可以分享您在项目中的使用方式,那就太好了!
我知道弱引用受垃圾收集器的支配,我们不能保证弱引用会存在。我看不出需要弱参考,但肯定应该有原因。
实际上,使用弱哈希图通常是一个坏主意。一方面它很容易出错,但更糟糕的是,它通常用于实现某种缓存。
这意味着以下内容:您的程序在一段时间内运行良好且性能良好,在压力下我们分配越来越多的内存(更多请求 = 更多内存压力 = 可能更多缓存条目),然后导致 GC。
现在突然间,当您的系统处于高压力下时,您不仅会获得 GC,而且还会丢失整个缓存,就在您最需要它的时候。这个问题不好玩,所以你至少必须使用一个合理大小的硬引用 LRU 缓存来缓解这个问题——你仍然可以使用weakrefs,但只是作为额外的帮助。
我已经看到不止一个项目受到该“错误”的影响。
我见过的最“明确合理”的弱引用使用是 Guava's Striped
,它执行锁条带化。基本上,如果当前没有线程持有对锁变量的引用,那么就没有理由保留该锁,是吗?那把锁过去可能已经使用过,但现在没有必要了。
如果我必须为您何时使用 which 给出一个规则,我会说当您将来可能使用某些东西时,软引用是更可取的,但如果您真的需要它可以重新计算它;当您可以确定在引用耗尽内存后永远不需要该值时,弱引用尤其可取。(例如,如果您对equals(Object)
映射键类型的特定实现使用默认引用相等,并且该对象停止在其他任何地方引用,那么您可以确定该条目将永远不会被再次引用。
The main reason for me to use weak references is indirectly, through a WeakHashMap.
You might want to store a collection of objects in a Map (as a cache or for any other reason), but don't want them to be in memory for as long as the Map exists, especially if the objects are relatively large.
By using a WeakHashMap, you can make sure that the reference from the Map isn't the only thing keeping the object in memory, since it'll be garbage collected if no other references exist.
假设只要一个对象被引用就需要保留一些信息,但你不知道它什么时候会消失,你可以使用弱引用来跟踪信息。
是的,它有很好的影响。
上面的“小部件序列号”问题的例子,最简单的方法是使用内置
WeakHashMap
类。WeakHashMap
工作原理完全一样HashMap
,除了键(不是值!)是使用弱引用来引用的。如果一个WeakHashMap
键变成垃圾,它的条目会被自动删除。这避免了我描述的陷阱,并且除了从 切换HashMap
到WeakHashMap
. 如果您遵循通过Map
接口引用地图的标准约定,则无需其他代码甚至知道更改。
JVM平台需要弱引用对象来确保防止内存泄漏。
正如 Java 开发人员应该知道的那样,Java 泄漏的可能性比预期的要多。在不再使用 Object 但某些集合仍然强烈引用该实例的情况下,此陈述尤其正确:一个非常简单但经常出现的内存泄漏示例,实际上在强引用存在之前不会释放内存区域。
在上述情况下,集合中的弱引用对象确保:没有强引用链,但只有弱链,实例可以被选为可收集的垃圾。
在我看来,Java 平台提供的所有功能在某种程度上都是有用的:非常熟练的程序员可以使 Java 变得快速可靠,就像 C++ 编写非常高质量的代码一样。
需要使Java 垃圾收集具有确定性。(从略带讽刺的角度来看,有些道理)。
WeakReference
当您想让一个对象进行垃圾收集而不必从其他持有引用的对象中优雅地删除自己时,A是很好的选择。
在发布-订阅或事件总线等场景中,会保存对订阅对象的引用集合。这些引用应该是弱引用,以便订阅者可以方便地超出范围而无需取消订阅。在应用程序中的所有其他地方都发布了他们的强引用之后,订阅者可以“消失”。到那时,订阅列表或事件总线就没有必要一直挂在订阅者身上了。的使用WeakReference
允许对象继续被遗忘。
订阅对象可能已在其不知情的情况下被订阅,由其他一些第 3 方对象提交到发布订阅或事件总线。在订阅者的生命周期后期协调取消订阅的调用可能非常麻烦。因此,让订阅者在没有正式退订的情况下消失可能会大大简化您的代码,并且可以避免在退订协调失败时出现困难的错误。
this.subscribersSet =
Collections.synchronizedSet(
Collections.newSetFromMap(
new WeakHashMap <>()
)
);
请注意,直到垃圾收集实际执行之后,集合中的条目才真正被删除,如上面链接的答案中所述。虽然作为垃圾收集的候选者存在(在任何地方都没有剩余的强引用),但该项目仍保留在集合中。