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.
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
@dasblinkenlight fair genug, lass es uns dann offen halten. –