我正在研究一个简单的LINQ查询的内存影响,并注意到LINQ查询创建了2个类型Enumerable+WhereListIterator
和的额外对象Func
.
使用的代码是这样的:
static void Main(string[] args) { // Setting baseline snapshot var list1 = new List{ 4862, 6541, 7841 }; var list2 = new List (list1.Count); var list3 = new List (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(); }
在foreach
循环之后的快照中,我注意到Enumerable+WhereListIterator
对象是垃圾收集但Func
仍然在内存中.
为什么这仍然存在?在那个时间点(在Console.Read
声明中)我认为没有任何东西仍在引用它,并且探测器强制GC(这就是收集迭代器的原因).
注意:收集其他快照不会改变释放的对象数量,因此不需要Func
为下次运行标记为集合.
lambda不是GC-ed的原因是lambda本身的结构:
item => item > 5000 && item < 7000
这个lambda不捕获任何东西,这意味着它可以编译一次,并永远重用.C#发现了这一点,并通过静态缓存它们以利用lambdas来提高性能.
如果你的lambda从它的上下文中捕获了一个变量,那么当它不再需要时就会被垃圾收集.
有关.NET中lambda生存期的更多信息,请参阅此答案.