清理 .net WeakReferences 的缓存
Cleaning up a cache of .net WeakReferences
在我的应用程序中,我有一个 Dictionary<int, WeakReference<Foo>>
来缓存从文件中读取的 Foo
s,其中键是文件中的索引。由于 Foo
是可变的,只要在该索引处对 Foo
的任何引用都必须保持活动状态(以便任何持有者以及从 Foo
来源)。
一旦 Foo
完全未被引用,我想删除 Dictionary
条目。我最初的想法是将 Foo
的终结器从缓存中删除,但这会导致在缓存插入时触发 GC 时内部状态不一致。我试图牢记终结器不能用于托管内存的概念。那么有没有办法做到这一点?
在我看来,您正在寻找的是一个 ConditionalWeakTable<TKey, TValue>
,您将 Foo
存储为您的键,而不是您的值:
The ConditionalWeakTable class differs from other
collection objects in its management of the object lifetime of keys
stored in the collection. Ordinarily, when an object is stored in a
collection, its lifetime lasts until it is removed (and there are no
additional references to the object) or until the collection object
itself is destroyed. However, in the ConditionalWeakTable class, adding a key/value pair to the table does not ensure
that the key will persist, even if it can be reached directly from a
value stored in the table (for example, if the table contains one key,
A, with a value V1, and a second key, B, with a value P2 that contains
a reference to A). Instead, ConditionalWeakTable
automatically removes the key/value entry as soon as no other
references to a key exist outside the table.
我最终用我正在调用的项目解决了这个问题 BackgroundFinalizer (source on github)。本质上,这允许您定义一个 "finalizer",它在垃圾收集期间不是 运行,而是在后台 运行。所以在我这里的特殊情况下,当 Foo
被垃圾收集时,一个从缓存中删除条目的函数被调度到独立于 GC 的工作线程中的 运行 ,所以我们避免了任何阻塞情况处于终结器或不一致的内部状态。
由于无法在对象被取消引用时自动删除 Dictionary
条目,另一个想法是在了解它后立即通过编写 cache-getting 函数自行删除它像那样:
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;
}
在我的应用程序中,我有一个 Dictionary<int, WeakReference<Foo>>
来缓存从文件中读取的 Foo
s,其中键是文件中的索引。由于 Foo
是可变的,只要在该索引处对 Foo
的任何引用都必须保持活动状态(以便任何持有者以及从 Foo
来源)。
一旦 Foo
完全未被引用,我想删除 Dictionary
条目。我最初的想法是将 Foo
的终结器从缓存中删除,但这会导致在缓存插入时触发 GC 时内部状态不一致。我试图牢记终结器不能用于托管内存的概念。那么有没有办法做到这一点?
在我看来,您正在寻找的是一个 ConditionalWeakTable<TKey, TValue>
,您将 Foo
存储为您的键,而不是您的值:
The ConditionalWeakTable class differs from other collection objects in its management of the object lifetime of keys stored in the collection. Ordinarily, when an object is stored in a collection, its lifetime lasts until it is removed (and there are no additional references to the object) or until the collection object itself is destroyed. However, in the ConditionalWeakTable class, adding a key/value pair to the table does not ensure that the key will persist, even if it can be reached directly from a value stored in the table (for example, if the table contains one key, A, with a value V1, and a second key, B, with a value P2 that contains a reference to A). Instead, ConditionalWeakTable automatically removes the key/value entry as soon as no other references to a key exist outside the table.
我最终用我正在调用的项目解决了这个问题 BackgroundFinalizer (source on github)。本质上,这允许您定义一个 "finalizer",它在垃圾收集期间不是 运行,而是在后台 运行。所以在我这里的特殊情况下,当 Foo
被垃圾收集时,一个从缓存中删除条目的函数被调度到独立于 GC 的工作线程中的 运行 ,所以我们避免了任何阻塞情况处于终结器或不一致的内部状态。
由于无法在对象被取消引用时自动删除 Dictionary
条目,另一个想法是在了解它后立即通过编写 cache-getting 函数自行删除它像那样:
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;
}