2010-07-01 65 views
1

我有一个关于如何在linq查询中处理垃圾回收的问题。 假设我有一个要处理的请求列表。每个请求都会生成一个非常大的一组数据,但是之后会应用一个过滤器来仅保留来自每个请求负载的关键数据。linq查询中的垃圾回收

//Input data 
List<request> requests; 
IEnumerable<filteredData> results = requests.Select(request => Process(request)).Select(data => Filter(data)); 

所以我知道查询延迟每个数据项,直到每个过滤的数据项被请求,所以这很好。但是,这个中间记忆强烈的部分是否会一直持续到可枚举成立?

我希望发生的事情是每个数据元素都可以在通过筛选阶段后立即进行垃圾回收,从而确保我有足够的内存来处理整个列表。这是这种情况,还是中间枚举可以保持一切,直到整个查询结束?如果是这样,是否有解决这个问题的方法?


注:过程()函数生成的内存密集型数据......这就是我很担心

回答

3

只要Process(...)返回值和Filter(...)不持有的所有引用在内部使用“大数据项”,那么在该过程中使用的内存应该变为无根,并且处理每个元素之后的GC候选项。

这并不意味着它会被收集,只是它会成为候选人。如果内存压力过高,GC很可能会收集它。

+0

凉爽。我的担心是从第一个select中间可枚举将持有数据,直到它完成 – tbischel 2010-07-01 18:47:18

+0

@tbischel:Nope - LINQ不会持有引用,除了添加到集合的引用之外,等等。只要没有引用,它可以被GCed。 – 2010-07-01 18:50:42

0

这是很难回答你的问题,因为你已经张贴不会真正编译(Select产生IEnumerable<T>什么,但你将其分配到List<T>。假设Filter(data)函数返回一个filteredData,你必须在查询上调用ToList()以将其存储在results中)。

requests我假设已经填充了数据。该列表将遵循正常的垃圾收集规则。我假设你担心的是Process函数的结果。我不能特别说明会发生什么,因为我也不知道你的功能在做什么。除非Filter函数的结果持有对其参数的引用(换句话说,Process函数的结果),否则Process创建的对象在查询完成后将完全超出范围,并且将遵循正常垃圾收集规则。

请记住,这些规则管辖资格收集。在您的应用程序的生命周期中,不会保证收集任何对象。但是,结果将符合条件,因此GC将会通过收集它们。

+0

修正了......没有从文件复制,所以是的,这是一个oversite – tbischel 2010-07-01 18:48:45

3

垃圾收集器在.NET中非常具有侵略性,可以在中间对象 不再被引用时甚至在内部循环中清除。事实上,在某些情况下,它会清理仍然被引用的对象,如果它可以看到它永远不会被再次访问。

运行这段代码显示了对象相当迅速清理,不挂有关直至查询结束(这不可能发生):

public class MyClass1 { ~MyClass1() { Console.WriteLine("Cleaned up MyClass1"); } } 
public class MyClass2 { ~MyClass2() { Console.WriteLine("Cleaned up MyClass2"); } } 

public class Program 
{ 
    static IEnumerable<MyClass1> lotsOfObjects() 
    { 
     while (true) 
      yield return new MyClass1(); 
    } 

    static void Main() 
    { 
     var query = lotsOfObjects().Select(x => foo(x)); 
     foreach (MyClass2 x in query) 
      query.ToString(); 
    } 

    static MyClass2 foo(MyClass1 x) 
    { 
     return new MyClass2(); 
    } 
} 

结果:

 
Cleaned up MyClass1 
Cleaned up MyClass1 
Cleaned up MyClass1 
Cleaned up MyClass2 
Cleaned up MyClass2 
Cleaned up MyClass1 
Cleaned up MyClass2 
etc...