C# 线程本地时内存泄漏<;T>;在循环图中使用

C# 线程本地时内存泄漏<;T>;在循环图中使用,c#,.net,memory-leaks,garbage-collection,.net-4.5,C#,.net,Memory Leaks,Garbage Collection,.net 4.5,我刚刚遇到垃圾收集器关于System.Threading.ThreadLocal的奇怪“行为”,我无法解释。在正常情况下,ThreadLocal实例在超出作用域时将被垃圾收集,即使它们没有被正确地处理,除非它们是循环对象图的一部分 以下示例演示了该问题: public class Program { public class B { public A A; } public class A { public ThreadLocal<B> LocalB; }

我刚刚遇到垃圾收集器关于
System.Threading.ThreadLocal
的奇怪“行为”,我无法解释。在正常情况下,
ThreadLocal
实例在超出作用域时将被垃圾收集,即使它们没有被正确地处理,除非它们是循环对象图的一部分

以下示例演示了该问题:

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();
    }
}
公共类程序
{
公共类B{public A A;}
公共类A{public ThreadLocal LocalB;}
私有静态列表引用=新列表();
静态void Main(字符串[]参数){
对于(变量i=0;i<1000;i++)
CreateGraph();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
//应打印0,但它打印1000
WriteLine(references.Count(c=>c.IsAlive));
}
静态void CreateGraph(){
var a=newa{LocalB=newthreadlocal()};
a、 LocalB.Value=newb{a=a};
参考文献。添加(新的WeakReference(a));
//如果以下任一行未注释,则循环
//图形被破坏,程序输出将变为0。
//a.LocalB=null;
//a.LocalB.Value=null;
//a.LocalB.Value.a=null;
//a.LocalB.Dispose();
}
}
虽然不调用
Dispose
不是一种好的做法,但CLR的设计是最终清理资源(通过调用终结器),即使没有调用
Dispose

为什么
ThreadLocal
在这方面表现不同,并且在循环图的情况下如果处理不当会导致内存泄漏?这是故意的吗?如果是这样的话,在哪里有记录?或者这是CLR的GC中的一个bug


(在.NET 4.5下测试)。

原因是您没有调用Dispose。垃圾收集器将只清理具有终结器作为最后手段的对象。

微软认为这实际上是一个bug。

确认这是一个bug。您是否有指向确切推文/问题的链接?你最初的评论是去年10月发表的,所以这里的上下文有点不清楚。虽然这条推文理论上可以回答这个问题,但这里要包括推文的基本部分。这是因为twitter可能会被少数用户(在大学/行业)屏蔽。请查看更多详细信息。