清理.net WeakReferences的缓存

时间:2015-04-21 13:52:06

标签: .net caching garbage-collection weak-references finalizer

在我的应用程序中,我有Dictionary<int, WeakReference<Foo>>来缓存Foo从文件中读取的内容,其中键是文件中的索引。由于Foo是可变的,因此只要对该索引处的Foo进行任何引用,缓存条目就必须保持活动状态(以便任何持有者以及从{ {1}}来源)。

我希望在Foo完全未引用后删除Dictionary条目。我最初的想法是将Foo的终结器从缓存中移除,但是当在缓存插入时触发GC时,这导致内部状态不一致。我试图理解终结器不能用于托管内存的概念。有没有办法做到这一点?

3 个答案:

答案 0 :(得分:1)

在我看来,您正在寻找的是ConditionalWeakTable<TKey, TValue>,您将Foo作为关键字存储,而不是您的价值:

  

ConditionalWeakTable类与其他类不同   集合对象在其管理对象的生命周期中   存储在集合中。通常,当一个对象存储在一个   收集,它的寿命持续到它被删除(并且没有   对对象的附加引用)或直到集合对象   本身就被摧毁了但是,在ConditionalWeakTable类中,向表中添加键/值对无法确保   密钥将持续存在,即使它可以直接从a到达   存储在表中的值(例如,如果表包含一个键,   A,值为V1,第二个键B,其值为P2   提及A)。相反, ConditionalWeakTable   没有其他人就会自动删除键/值条目   表格之外存在对密钥的引用。

答案 1 :(得分:0)

我最后通过一个项目来解决这个问题,我打电话给BackgroundFinalizergithub上的来源)。从本质上讲,这可以让你定义一个&#34;终结者&#34;在垃圾收集期间不运行,而是在后台运行。所以在我的特殊情况下,当Foo被垃圾收集时,从缓存中删除条目的函数被安排在独立于GC的工作线程中运行,因此我们避免在终结器中阻塞任何情况或内部状态不一致。

答案 2 :(得分:0)

由于取消引用后无法自动删除Dictionary条目,所以另一个想法是,一旦了解该知识,就可以通过编写如下这样的缓存获取函数将其自己删除:< / p>

private readonly Dictionary<int,WeakReference<Foo>> _dict;
public bool TryGetItem(int key, out Foo item) {
    if (_dict.TryGetvalue(key, out var wr)) {
        if (wr.TryGetTarget(out item))
            return true;
        else
            // The weak reference is dead. We remove the dictionary entry.
            _dict.Remove(key);
    }
    return false;
}