我刚刚遇到垃圾收集器关于 System.Threading.ThreadLocal<T>
的奇怪“行为”我无法解释。一般情况下,ThreadLocal<T>
实例超出范围时将被垃圾收集,即使它们没有被正确处理,除非它们是循环对象图的一部分。
下面的例子演示了这个问题:
public class Program
{
public class B { public A A; }
public class A { public ThreadLocal<B> LocalB; }
private static List<WeakReference> references = new List<WeakReference>();
static void Main(string[] args) {
for (var i = 0; i < 1000; i++)
CreateGraph();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
// Expecting to print 0, but it prints 1000
Console.WriteLine(references.Count(c => c.IsAlive));
}
static void CreateGraph() {
var a = new A { LocalB = new ThreadLocal<B>() };
a.LocalB.Value = new B { A = a };
references.Add(new WeakReference(a));
// If either one of the following lines is uncommented, the cyclic
// graph is broken, and the programs output will become 0.
// a.LocalB = null;
// a.LocalB.Value = null;
// a.LocalB.Value.A = null;
// a.LocalB.Dispose();
}
}
虽然没有调用 Dispose
这不是好的做法,但最终清理资源(通过调用终结器)是 CLR 的设计,即使 Dispose
也是如此。不被调用。
为什么 ThreadLocal
在这方面表现不同,并且在循环图的情况下如果处理不当会导致内存泄漏?这是设计使然吗?如果是这样,这在哪里记录?或者这是 CLR 的 GC 中的错误?
(在 .NET 4.5 下测试)。
最佳答案
微软的David Kean confirmed这实际上是一个错误。
关于c# - 在循环图中使用 ThreadLocal<T> 时发生内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33172615/