我在Aleksey shimilev的幻灯片"弦乐教理"(https://///////shospall/talks/joker-oct-oct-oct-2014-----------------------------------------------------------------------------------------------------------------------------------------------49 ff)。许多Java程序员都知道string.intern()的实践概念。
但是,如果不使用弱参考,将是潜在的内存泄漏。我想知道对于具有弱哈希地图的Dewuplicator来说,正确实现了。我倾向于选择B,但我不确定。
选项A:使用弱hashmap就足够了。"弱键"可确保当对象不再使用时将其删除。
示例实现:
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:使用弱hashmap是不够的。所有值都必须是弱论,因为复杂的WeakhashMapdEduplicator的实例强烈引用了弱的哈希映射,该图将数组强烈地引用了一个条目,其中一个条目强烈引用了该值。只有密钥被地图引用。我在哪里错了?
示例实现:
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;
}
}
这将阻止您的缓存值泄漏,但是值得一提的是,在发布旧值时,您想多么渴望。如果您的价值观往往是短暂的,但预计会一次又一次弹出,则可能需要更长的时间。在这种情况下,您可以考虑将SoftReference
用作值包装器。软引用的行为类似,但它们倾向于坚持其指南,直到面对记忆压力。Oracle的"服务器" VM(X64的默认值)更喜欢扩展堆而不是发布软引用,因此您的应用程序的内存使用情况可能会更快地达到其限制,此时它将开始驱逐不可到达的值。这是一个权衡,也不是"一个尺寸适合所有"解决方案。灵活的实现可能会将参考创建化为可插入的策略,从而使您在首次创建缓存时在弱和软引用之间进行选择。
我忽略了弱hashmap的Javadoc中的以下评论:
实施注意:弱hashmap中的值对象由 普通的强参考。因此,应注意确保 价值对象不会直接指他们自己的钥匙 或间接地,因为这将阻止钥匙被丢弃。 请注意,值对象可以间接地引用其键 虚弱也就是说,一个值对象可能强烈指一些 其他关键对象,其关联的价值对象反过来强烈 请参考第一个值对象的密钥。如果地图中的值 不要依靠地图对它们有很大的参考,一种方法 处理这个问题是将价值观包裹在弱点中 在插入之前,如:m.put(键,新的弱rereference(value))和 然后解开每个获取。