map = new HashMap<>(); map.put("Bob", n-6ren">
gpt4 book ai didi

java - 如果不明确清理 HashMap> 是否会导致内存泄漏?

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:02:48 24 4
gpt4 key购买 nike

我遇到过一段代码,我确信它会导致无意中的内存泄漏:

Object user = getUser("Bob");

Map<String, WeakReference<Object>> map = new HashMap<>();
map.put("Bob", new WeakReference( user ) );

这个映射的目的是缓存对象,并在它们不再被强引用时让 GC 自动从映射中清除它们。

但是,我的看法是,如果键也不是弱引用,那么一旦对象被 GC 处理,散列映射中仍然会有一个键指向 null 的条目。因此, map 仍将包含相同数量的行,只是所有行都指向空值。

所以在上面的例子中,一旦所有对 user 的强引用都被释放,并且 GC 销毁了 Object,映射中的条目将等同于:

map.put("Bob", null );

因此,除非有清理例程用空值刷新所有键,否则我的 map 将继续增长。

那么问题就变成了如何解决这个问题?有没有我可以使用的映射结构,如果值被破坏,它会自动刷新我的条目?

我打算做这样的事情:

Object user = getUser("Bob");

Map<String, WeakReference<Object>> map = new WeakHashMap<>();
map.put(user.getUsername(), new WeakReference( user ) );

但这似乎是一个非常有限的用例,其中我的键必须是从我的值中检索到的对象。对于 WeakHashMap,我的键不能是字符串常量(即:“Bob”),否则不会有任何其他对它的引用,GC 将从我的映射中清除该对象。

是否有其他一些缓存结构可以提供所有这些功能?

最佳答案

你是对的,引用对象的集合不会删除映射,但是,结果不等同于

map.put("Bob", null );

它将等同于

map.put("Bob", new WeakReference<>(null) );

所以你不仅有一个悬空条目实例,还有一个悬空清除的WeakReference实例。

当你使用

Map<String, WeakReference<User>> map = new WeakHashMap<>();
User user = getUser("Bob");
map.put(user.getUsername(), new WeakReference( user ) );

假设 user.getUsername() 返回对存储在 User 对象中的字符串实例的引用,您将获得所需的语义,以确保它保持强可达性只要 User 是强可达的。

我没有看到这里有任何限制。由于存储在 User 中的字符串实例确实存在,因此只要 User 实例存在,引用与映射键完全相同的字符串实例就没有开销。您仍然可以使用字符串常量作为查找键 User u = map.get("Bob");,因为它们的相等性仍然根据 String.hashCode()String.equals()。如果您使用字符串常量 "Bob" 放置 映射,则至少只要包含常量的 code 还存在,映射通常就会持续存在(以及在此生命周期中使用相同文字的每个其他代码),可能是整个应用程序。但是,使用与存储在引用对象中不同的字符串实例作为键有什么意义呢?

请注意 WeakHashMap 必须处理相同的问题,条目不会自动删除。它必须使用 ReferenceQueue发现何时收集了引用对象以从表中删除其关联条目。 This cleanup每当您对其调用方法时都会发生,因此当您不对其调用方法时,表将不会得到清理,但由于每次插入都会发生这种清理,因此您可以免受不断增长的情况的影响。

关于java - 如果不明确清理 HashMap<String, WeakReference<>> 是否会导致内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46230629/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com