我在 Aleksey Shipilev 的幻灯片“字符串教义问答”(https://shipilev.net/talks/joker-Oct2014-string-catechism.pdf,幻灯片 49 ff)中发现了“重复数据删除器”的概念。许多 Java 程序员都知道 String.intern() 中类似的实习概念。
但是,如果不使用弱引用,重复数据删除器可能会导致内存泄漏。
我想知 Prop 有弱 HashMap 的重复数据删除器的正确实现应该是什么样子。我倾向于选项 B,但我不确定。
选项A: 使用 WeakHashMap 就足够了。 “弱键”确保对象在不再使用时被删除。
示例实现:
public class SimpleWeakHashMapDeduplicator {
private final WeakHashMap<Object, Object> weakHashMap = new WeakHashMap<>();
public Object deduplicate(Object potentialDuplicate) {
if(potentialDuplicate == null) {
return null;
} else {
return weakHashMap.computeIfAbsent(potentialDuplicate, (key)->key);
}
}
}
选项B: 使用 WeakHashMap 是不够的。所有值都必须是 WeakReferences,因为 ComplicatedWeakHashMapDeduplicator 的实例强烈引用弱 HashMap ,该映射强烈引用带有条目的数组,其中一个条目强烈引用该值。只有键被映射弱引用。我哪里错了?
示例实现:
public class ComplicatedWeakHashMapDeduplicator {
private final WeakHashMap<Object, WeakReference<Object>> weakHashMap = new WeakHashMap<>();
public Object deduplicate(Object potentialDuplicate) {
if(potentialDuplicate == null) {
return null;
} else {
return weakHashMap.computeIfAbsent(potentialDuplicate, WeakReference::new).get();
}
}
}
你觉得怎么样?
最佳答案
“选项 B”的方向是正确的,但还没有完全实现。此行有问题:
return weakHashMap.computeIfAbsent(potentialDuplicate, WeakReference::new).get();
让我们假设弱映射包含先前缓存的值。您调用computeIfAbsent并获取弱引用。在您 get()
之前的短暂窗口期间,没有什么可以阻止垃圾收集器回收其所指对象。如果发生这种情况,您最终将返回 null
。
你的逻辑需要更加稳健一些。尝试这样的事情:
public final class WeakCache<T> {
private final WeakHashMap<T, WeakReference<T>> _map = new WeakHashMap<>();
public synchronized T cache(final T value) {
if (value == null) {
return null;
}
final WeakReference<T> oldReference = _map.get(value);
if (oldReference != null) {
final T oldValue = oldReference.get();
if (oldValue != null) {
return oldValue;
}
}
_map.put(value, new WeakReference<>(value));
return value;
}
}
这将防止您的缓存值泄漏,但值得询问的是您在释放旧值时有多渴望。如果你的值(value)观往往是短暂的,但预计会一次又一次地出现,你可能想坚持更长时间。在这种情况下,您可以考虑使用 SoftReference 作为值包装器。软引用的行为类似,但它们倾向于保留其引用对象,直到面临内存压力。 Oracle 的“服务器”VM(x64 的默认值)更愿意扩展堆而不是释放软引用,因此应用程序的内存使用量可能会更快达到极限,此时它将开始驱逐无法访问的值。这是一种权衡,也不是“一刀切”的解决方案。灵活的实现可能会将引用创建抽象为可插入策略,从而在首次创建缓存时在弱引用和软引用之间进行选择变得很简单。
关于java - 对于具有弱 HashMap 的重复数据删除器,正确的实现是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46183578/