【问题标题】:Memory leak when ThreadLocal<T> is used in cyclic graph循环图中使用 ThreadLocal<T> 时的内存泄漏
【发布时间】:2015-10-16 14:12:05
【问题描述】:

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

下面的例子演示了这个问题:

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 下测试)。

【问题讨论】:

标签: c# .net memory-leaks garbage-collection .net-4.5


【解决方案1】:

Microsoft 的 David Kean confirmed 认为这实际上是一个错误。

【讨论】:

  • 您有指向确切推文/问题的链接吗?您最初的评论来自去年 10 月,所以这里的上下文有点丢失。
  • 虽然推文理论上可以回答问题,it would be preferable 在此处包含推文的基本部分。这是因为 Twitter 可能会被少数用户(大学/行业)屏蔽。请查看this meta post 了解更多详情。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2022-06-10
    • 2011-11-25
    • 2013-07-31
    • 2011-12-16
    • 2015-12-28
    • 2014-07-30
    • 2014-09-08
    • 2014-05-17
    • 1970-01-01
    相关资源
    最近更新 更多