Sch*_*999 5 c# collections concurrency garbage-collection .net-4.0
我惊讶地发现我的应用程序内存占用不断增长 - 运行时间越长,消耗的内存就越多。因此,windbg
我用一些魔法指出了我基于ConcurrentDictionary
. CD 有很多对我来说非常酷的好处(其中之一是它的数据永远不会在 LOH 中结束)。TryAdd
和TryRemove
是用于添加和驱逐项目的两种方法。!gcroot
一些较旧的元素引导我回到我的缓存。ILSpy 的一些调查使我得出了这个结论:
TryRemove
并没有真正删除一个元素。它所做的只是更改链表指针以跳过从不将数组元素的值分配给null
. 这可以防止 GC 收集旧的驱逐对象。
真的吗?这是一个已知的问题吗?如果是这样,我唯一的选择是TryUpdate(key, null)
然后TryRemove(key)
?如果是这样,那么我必须锁定ConcurrentDictionary
访问权限,这是矛盾的。
这是 ILSpy 转储:
// System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>
private bool TryRemoveInternal(TKey key, out TValue value, bool matchValue, TValue oldValue)
{
while (true)
{
ConcurrentDictionary<TKey, TValue>.Tables tables = this.m_tables;
int num;
int num2;
this.GetBucketAndLockNo(this.m_comparer.GetHashCode(key), out num, out num2, tables.m_buckets.Length, tables.m_locks.Length);
lock (tables.m_locks[num2])
{
if (tables != this.m_tables)
{
continue;
}
ConcurrentDictionary<TKey, TValue>.Node node = null;
ConcurrentDictionary<TKey, TValue>.Node node2 = tables.m_buckets[num];
while (node2 != null)
{
if (this.m_comparer.Equals(node2.m_key, key))
{
bool result;
if (matchValue && !EqualityComparer<TValue>.Default.Equals(oldValue, node2.m_value))
{
value = default(TValue);
result = false;
return result;
}
if (node == null)
{
Volatile.Write<ConcurrentDictionary<TKey, TValue>.Node>(ref tables.m_buckets[num], node2.m_next);
}
else
{
node.m_next = node2.m_next;
}
value = node2.m_value;
tables.m_countPerLock[num2]--;
result = true;
return result;
}
else
{
node = node2;
node2 = node2.m_next;
}
}
}
break;
}
value = default(TValue);
return false;
}
Run Code Online (Sandbox Code Playgroud)