2015-10-16 5 views
6

Ich bin gerade auf dieses seltsame "Verhalten" des Garbage Collector bezüglich System.Threading.ThreadLocal<T> gestoßen, das ich nicht erklären kann. Unter normalen Umständen werden ThreadLocal<T> Instanzen als Garbage Collected erfasst, wenn sie außerhalb des Gültigkeitsbereichs liegen, auch wenn sie nicht ordnungsgemäß entsorgt werden, außer in den Fällen, in denen sie Teil eines zyklischen Objektdiagramms sind.Speicherleck, wenn ThreadLocal <T> in zyklischen Graphen verwendet wird

Das folgende Beispiel zeigt das Problem:

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(); 
    } 
} 

Obwohl nicht Dispose nicht gute Praxis nennen, aber es ist das Design der CLR Ressource zu bereinigen (durch die Finalizerthread Aufruf) schließlich, auch wenn Dispose nicht aufgerufen .

Warum verhält sich ThreadLocal in dieser Hinsicht anders und kann Speicherlecks verursachen, wenn sie im Falle eines zyklischen Graphen nicht ordnungsgemäß entsorgt werden? Ist das Absicht? Und wenn ja, wo ist das dokumentiert? Oder ist das ein Fehler im GC der CLR?

(Getestet unter .NET 4.5).

+0

[David Kean] (https://twitter.com/davkean) bestätigte, dass dies ein Fehler ist. – Steven

+0

[Klicken Sie auf] (https://mobile.twitter.com/davkean/status/655067698511024128). – Steven

Antwort

0

Microsofts David Keanconfirmed, dass dies tatsächlich ein Fehler ist.

+0

Haben Sie einen Link zum genauen Tweet/Problem? Dein ursprünglicher Kommentar stammt vom Oktober letzten Jahres, daher ist der Kontext hier ein wenig verloren. –

+0

@JeffDammeyer Ich habe meine Antwort mit einem Link aktualisiert. – Steven

+0

Während der Tweet theoretisch die Frage beantworten könnte, [wäre es vorzuziehen] (// meta.stackoverflow.com/q/8259), die wesentlichen Teile des Tweets hier einzubeziehen. Dies liegt daran, dass Twitter für einige Benutzer (in der Hochschule/Industrie) blockiert sein kann. Werfen Sie einen Blick auf [diesen Meta-Beitrag] (http://meta.stackoverflow.com/a/313037/4099593) für weitere Details. –

-3

Der Grund ist, dass Sie Dispose nicht anrufen. Der Garbage Collector bereinigt nur Objekte, die Finalizer als letzte Möglichkeit haben.

+2

Und raten Sie mal ... 'TheadLocal ' tatsächlich * hat * einen Finalizer. – Steven

Verwandte Themen