对于具有弱哈希地图的Dewuplicator的正确实现是什么?



我在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))和 然后解开每个获取。

相关内容

  • 没有找到相关文章

最新更新