如何避免使用LINQ-To-SQL导致内存泄漏?

时间:2020-03-06 14:37:11  来源:igfitidea点击:

LINQ-To-SQL在内存使用方面一直存在一些问题。我在Windows服务中使用它来进行一些处理,并且正在遍历从上下文中拉回的大量数据。是的,我知道我可以使用存储过程来做到这一点,但是出于某些原因,这不是一个理想的解决方案。

无论如何,我基本上看到的是即使调用context.SubmitChanges()也不会释放内存。因此,我最终不得不做各种奇怪的事情,例如一次只能拉回100条记录,或者创建多个上下文并使它们全部执行单独的任务。如果我保持相同的DataContext并稍后将其用于其他调用,它将消耗越来越多的内存。即使我在查询返回给我的" var tableRows"数组上调用" Clear()",将其设置为null,然后调用" SYstem.GC.Collect()",它仍然不会释放内存。

现在,我已经阅读了一些有关如何快速使用" DataContexts"并快速处理它们的信息,但是似乎它们应该是一种强制上下文转储其所有数据(或者特定表的所有跟踪数据)的方式。 ),以确保内存可用。

有人知道哪些步骤可以保证释放内存吗?

解决方案

DataContext跟踪它曾经获取的所有对象。直到垃圾被收集,它才会释放它。同样,当它实现IDisposable时,必须调用Dispose或者使用using语句。

这是正确的方法:

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

如果不需要对象跟踪,请将DataContext.ObjectTrackingEnabled设置为false。如果确实需要它,则可以使用反射来调用内部DataContext.ClearCache(),尽管我们必须知道,由于它是内部的,因此它会在框架的将来版本中消失。据我所知,框架本身不使用它,但是确实清除了对象缓存。

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

似乎我们主要关心的是创建和处置一堆DataContext对象。这就是linq2sql的设计方式。 DataContext的生命周期较短。由于我们要从数据库中提取大量数据,因此有大量的内存使用是有意义的。通过分块处理数据,我们将走上正确的道路。

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

谢谢大家,我将检查ClearCache方法。只是为了澄清(供将来的读者使用),我得到内存使用的情况是这样的:

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
   }
}