如何避免使用LINQ到SQL的内存泄漏?


20

我一直在使用LINQ-to-SQL存在一些问题。我在Windows服务中使用它来做一些处理,并且我正在循环大量从上下文中撤回的数据。是的 - 我知道我可以用存储过程来做到这一点,但有理由说这是一个不太理想的解决方案。

无论如何,我基本上看到的是内存不被释放,即使我打电话context.SubmitChanges()后。所以我最终不得不做各种奇怪的事情,比如只在时间拉回100条记录,或者创建几个上下文,让他们都做单独的任务。如果我保留相同的DataContext并稍后将其用于其他呼叫,则它只会占用越来越多的内存。即使我在查询返回给我的“var tableRows”数组上调用Clear(),将其设置为null,并调用SYstem.GC.Collect() - 它仍然不释放内存。

现在我已阅读了一些关于如何快速使用DataContexts并快速处理它们的方法,但似乎他们应该是强制上下文将所有数据(或其所有跟踪数据特定的表格)以确保内存是免费的。

任何人都知道哪些步骤可以保证内存被释放?

15

如果您不需要对象跟踪设置DataContext.ObjectTrackingEnabled。如果你确实需要它,你可以使用反射来调用内部的DataContext.ClearCache(),虽然你必须知道,因为它的内部,它将在未来的框架版本中消失。据我所知,框架本身并没有使用它,但它清除对象缓存确实

+1

注意正如其他先生们所说,在这种情况下使用多个DataContexts可能会更好。但是,由于问题是如何保证在一个上下文中释放内存,ClearCache()方法更接近答案。 24 9月. 082008-09-24 14:43:13

  0

是的,使用或不是很多的datacontext取决于你的数据量,你可以学习如何处理这个,我从RobConery MVC Road系列中学习... http://blog.wekeroad.com/category/mvc-storefront 04 9月. 092009-09-04 15:01:53

+3

这里是你如何可以调用ClearCache():context.GetType()InvokeMember( \t “ClearCache”, \t BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, \t空,背景,NULL); 08 11月. 102010-11-08 16:42:34

  0

+1,但我发现我需要一个更多的绑定标志来告诉它调用方法:BindingFlags.InvokeMethod。 11 11月. 102010-11-11 21:38:05

  0

我试图'DataContext.ObjectTrackingEnabled为false',但是当我运行内存分析器'它表明这是作为处置,但不能被GCed。 23 1月. 132013-01-23 09:58:32


20

DataContext跟踪它曾经获取的所有对象。在收集垃圾之前它不会释放它。此外,由于它实施IDisposable,您必须致电Dispose或使用using声明。

这是正确的方式去:

using(DataContext myDC = new DataContext) 
{ 
    // Do stuff 
} //DataContext is disposed 

6

正如David指出的那样,您应该使用using块来处理DataContext。

看来您的主要关注点是创建和配置一堆DataContext对象。这是linq2sql的设计。 DataContext的使用寿命很短。由于您从数据库中提取大量数据,因此会有很多内存使用情况。通过以块处理数据,您正处于正确的轨道上。

不要害怕创建大量的DataContexts。它们被设计成以这种方式使用。


3

谢谢你们 - 我将检查ClearCache方法。只是为了澄清(对于未来的读者),在我得到的内存usuage的情况是这样的:

using(DataContext context = new DataContext()) 
{ 
    while(true) 
    { 
     int skipAmount = 0; 
     var rows = context.tables.Select(x => x.Dept == "Dept").Skip(skipAmount).Take(100); 

     //break out of loop when out of rows 

     foreach(table t in rows) 
     { 
     //make changes to t 
     } 

     context.SubmitChanges(); 
     skipAmount += rows.Count(); 

     rows.Clear(); 
     rows = null; 

     //at this point, even though the rows have been cleared and changes have been 
     //submitted, the context is still holding onto a reference somewhere to the 
     //removed rows. So unless you create a new context, memory usuage keeps on growing 
    } 
} 

0

我只是碰到了类似的问题。在我的情况下,帮助建立属性DataContext.ObjectTrackingEnabled为false。 但它只如下工作在通过行迭代的情况:

using (var db = new DataContext()) 
{ 
    db.ObjectTrackingEnabled = false; 
    var documents = from d in db.GetTable<T>() 
        select d; 
    foreach (var doc in documents) 
    { 
     ... 
    } 
} 

如果,例如,在查询中使用的方法ToArray的()或ToList() - 不影响