2015-10-16 21 views
6

我剛剛遇到了垃圾回收器的這個奇怪的'行爲',涉及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下測試)。

+0

[David Kean](https://twitter.com/davkean)證實這是一個錯誤。 – Steven

+0

[點擊](https://mobile.twitter.com/davkean/status/655067698511024128)。 – Steven

回答

0

微軟的David Keanconfirmed這實際上是一個錯誤。

+0

你有一個精確的推文/問題的鏈接?你原來的評論是從去年10月份開始的,所以上下文有點失落。 –

+0

@JeffDammeyer我用鏈接更新了我的答案。 – Steven

+0

雖然推文理論上可以回答這個問題,但[這將是更可取的](// meta.stackoverflow.com/q/8259)在這裏包括推文的基本部分。這是因爲可能會阻止少數用戶(大學/行業)的Twitter。請查看[此meta post](http://meta.stackoverflow.com/a/313037/4099593)瞭解更多詳情。 –

-3

原因是你沒有調用Dispose。垃圾收集器將僅清理具有終結器的對象作爲最後的手段。

+2

並且猜猜......什麼......'TheadLocal '實際上*有*終結者。 – Steven