2015-12-20 2 views
10

Ich untersuchte die Auswirkungen einer einfachen LINQ-Abfrage auf den Speicher und bemerkte, dass die LINQ-Abfrage zwei zusätzliche Objekte der Typen Enumerable+WhereListIterator<Int32> und Func<Int32, Boolean> erstellte.Warum gibt ein GC nach einer LINQ-Abfrage den WhereListIterator frei, aber nicht den Func, der die Bedingung darstellt?

Der verwendete Code ist folgende:

static void Main(string[] args) 
{ 
    // Setting baseline snapshot 
    var list1 = new List<int> { 4862, 6541, 7841 }; 
    var list2 = new List<int>(list1.Count); 
    var list3 = new List<int>(list1.Count); 

    // First snapshot: LINQ usage 
    list2.AddRange(list1.Where(item => item > 5000 && item < 7000)); 

    // Second snapshot: foreach-loop 
    foreach (var item in list1) 
    { 
     if (item > 5000 && item < 7000) 
     { 
      list3.Add(item); 
     } 
    } 

    // End gather 
    Console.Read(); 
} 

Am snapshot nach der foreach Schleife I feststellen, dass das Objekt Enumerable+WhereListIterator<Int32> Müll gesammelt wird, ist aber die Func<Int32, Boolean> ist noch im Speicher.

Warum wird das immer noch herumgehalten? Zu diesem Zeitpunkt (unter der Console.Read-Anweisung) glaube ich nicht, dass irgendetwas darauf verweist und ein GC vom Profiler erzwungen wurde (weshalb der Iterator gesammelt wird).

Hinweis: Das Sammeln zusätzlicher Snapshots ändert nicht die Anzahl der freigegebenen Objekte. Es ist also keine Frage, ob Func für die nächste Ausführung markiert wird.

+0

Kommentar zur Wiedereröffnung der Frage: Obwohl die verknüpfte Frage eindeutig verwandt ist, fragt diese Frage nach einem bestimmten Fall und bietet eine Demo, um zu demonstrieren, was vor sich geht. – dasblinkenlight

+0

@dasblinkenlight fair genug, lass es uns dann offen halten. –

Antwort

11

Der Grund für das Lambda nicht ist GC-ed die Struktur des Lambdas selbst:

item => item > 5000 && item < 7000 

Dieses Lambda nicht Capture etwas bedeutet, dass es einmal kompiliert werden kann, und immer wieder verwendet werden. C# erkennt dies und nutzt Lambdas, indem es sie statisch zwischenspeichert, um die Leistung zu verbessern.

Hätte Ihr Lambda eine Variable aus seinem Kontext erfasst, wäre es Müll gesammelt worden, wenn es nicht mehr benötigt wird.

Weitere Informationen zur Lambda-Lebensdauer in .NET finden Sie unter this answer.

+0

Perfekt, das und die verknüpften Antworten erklären alles. –

Verwandte Themen