C# linq查询中的垃圾收集
我有一个关于如何在linq查询中处理垃圾收集的问题。 假设给我一个要处理的请求列表。每个请求都会生成一组非常大的数据,但随后会应用一个过滤器,仅保留来自每个请求负载的关键数据C# linq查询中的垃圾收集,c#,linq,garbage-collection,deferred-execution,C#,Linq,Garbage Collection,Deferred Execution,我有一个关于如何在linq查询中处理垃圾收集的问题。 假设给我一个要处理的请求列表。每个请求都会生成一组非常大的数据,但随后会应用一个过滤器,仅保留来自每个请求负载的关键数据 //Input data List<request> requests; IEnumerable<filteredData> results = requests.Select(request => Process(request)).Select(data => Filter(data
//Input data
List<request> requests;
IEnumerable<filteredData> results = requests.Select(request => Process(request)).Select(data => Filter(data));
//输入数据
列出请求;
IEnumerable results=requests.Select(请求=>Process(请求)).Select(数据=>Filter(数据));
所以我知道每个数据项的查询都会延迟,直到每个过滤的数据项被请求为止,所以这很好。但是,中间内存密集的部分会一直持续到枚举完成吗
我希望发生的是,每个数据元素一经过过滤阶段就可以被垃圾收集,从而确保我有足够的内存来处理整个列表。是这样的,还是中间的可枚举项在整个查询结束之前保留所有内容?如果是的话,有没有linq的方法来处理这个问题
注意:Process()函数生成内存密集型数据。。。这就是我所担心的只要
Process(…)
和Filter(…)
的返回值不包含任何对内部使用的“大数据项”的引用,那么在处理每个元素后,该进程中使用的内存应该是无根的,并且是GC的候选内存
这并不意味着它将被收集,只是它将是一个候选人。如果内存压力很大,GC很可能会收集它。很难回答您的问题,因为您发布的内容实际上不会编译(
Select
生成一个IEnumerable
,但您正在将其分配到列表中。假设过滤器(数据)
函数返回一个filteredData
,您必须对查询调用ToList()
,将其存储在结果中
请求
应该已经填充了数据。此列表将遵循正常的垃圾收集规则。我假设您担心的是过程的结果。我不能具体地说会发生什么,因为我也不知道你的过滤器
函数会做什么。除非Filter
函数的结果保留对其参数的引用(换句话说,Process
函数的结果),否则Process
创建的对象在查询完成后将完全超出范围,并将遵循正常的垃圾收集规则
请记住,这些规则适用于托收资格。在应用程序的生命周期内,不保证收集任何对象。但是,结果是合格的,因此GC将能够收集它们。垃圾收集器在.NET中非常具有攻击性,可以清理中间对象
当它们不再被引用时,甚至在循环内部。事实上,在某些情况下,它会清理仍然被引用的对象,如果它能看到它将永远不再被访问
运行此代码表明对象被清理得相当快,并且在查询完成之前不会挂起(它从来不会这样做):
公共类MyClass1{~MyClass1(){Console.WriteLine(“清理过的MyClass1”);}
公共类MyClass2{~MyClass2(){Console.WriteLine(“清理过的MyClass2”);}
公共课程
{
静态IEnumerable lotsOfObjects()
{
while(true)
收益率返回新MyClass1();
}
静态void Main()
{
var query=lotsOfObjects().Select(x=>foo(x));
foreach(查询中的MyClass2 x)
query.ToString();
}
静态MyClass2 foo(MyClass1 x)
{
返回新的MyClass2();
}
}
结果:
Cleaned up MyClass1
Cleaned up MyClass1
Cleaned up MyClass1
Cleaned up MyClass2
Cleaned up MyClass2
Cleaned up MyClass1
Cleaned up MyClass2
etc...
清理我的班级
清理我的班级
清理我的班级
清理我的班级2
清理我的班级2
清理我的班级
清理我的班级2
等
酷。我担心的是,从第一个select开始的中间枚举将保留数据,直到它被删除为止completed@tbischel:否-除了添加到集合中的引用之外,LINQ不会保存引用。只要没有引用,就可以进行GCD。修复了。。。不是从文件中复制的,所以是的,那是一个超站点
Cleaned up MyClass1
Cleaned up MyClass1
Cleaned up MyClass1
Cleaned up MyClass2
Cleaned up MyClass2
Cleaned up MyClass1
Cleaned up MyClass2
etc...