2015-10-16 7 views
6

Mi sono imbattuto in questo strano "comportamento" del Garbage Collector relativo a System.Threading.ThreadLocal<T> che non riesco a spiegare. In circostanze normali, le istanze di ThreadLocal<T> verranno eliminate dal garbage quando escono dall'ambito, anche se non sono disposte correttamente, tranne nel caso in cui facciano parte di un grafico di oggetti ciclici.Perdita di memoria quando ThreadLocal <T> viene utilizzato nel grafico ciclico

L'esempio seguente illustra il problema:

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

Anche se non chiamare Dispose non è buona pratica, ma è il design della CLR per liberare le risorse (chiamando il finalizzatore) alla fine, anche se Dispose non si chiama .

Perché il comportamento ThreadLocal si comporta in modo diverso a questo proposito e può causare perdite di memoria se non disposto correttamente in caso di un grafico ciclico? È questo in base alla progettazione? E se sì, dove è documentato? O si tratta di un bug nel GC del CLR?

(Testato in .NET 4.5).

+0

[David Kean] (https://twitter.com/davkean) ha confermato che si tratta di un bug. – Steven

+0

[Fare clic] (https://mobile.twitter.com/davkean/status/655067698511024128). – Steven

risposta

0

Microsoft's David Keanconfirmed che questo in realtà è un bug.

+0

Hai un collegamento al tweet/problema preciso? Il tuo commento originale è stato dall'ottobre dell'anno scorso, quindi il contesto è un po 'perso qui. –

+0

@JeffDammeyer Ho aggiornato la mia risposta con un collegamento. – Steven

+0

Mentre il tweet può teoricamente rispondere alla domanda, [sarebbe preferibile] (// meta.stackoverflow.com/q/8259) per includere qui le parti essenziali del tweet. Questo perché Twitter potrebbe essere bloccato per alcuni utenti (nel college/industria). Date un'occhiata a [questo meta post] (http://meta.stackoverflow.com/a/313037/4099593) per maggiori dettagli. –

-3

Il motivo è che non si chiama Dispose. Il garbage collector pulirà solo gli oggetti che hanno finalizzatori come ultima risorsa.

+2

E indovina cosa .... 'TheadLocal ' in realtà * ha * un finalizzatore. – Steven