【问题标题】:How do I avoid a memory leak with LINQ-To-SQL?如何避免使用 LINQ-To-SQL 的内存泄漏?
【发布时间】:2010-09-12 11:46:39
【问题描述】:

我在使用 LINQ-To-SQL 时遇到了一些关于内存使用的问题。我在 Windows 服务中使用它来进行一些处理,并且我正在循环访问大量从上下文中拉回的数据。是的 - 我知道我可以使用存储过程来做到这一点,但有一些原因表明这不是一个理想的解决方案。

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

现在我已经阅读了一些关于您应该如何快速使用 DataContexts 并快速处理它们的内容,但似乎它们应该是一种强制上下文转储其所有数据(或其所有跟踪数据)的方法一个特定的表)在某个点保证内存是空闲的。

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

【问题讨论】:

    标签: database linq linq-to-sql memory-management memory-leaks


    【解决方案1】:

    DataContext 跟踪它曾经获取的所有对象。在垃圾收集之前它不会释放它。此外,由于它实现了IDisposable,因此您必须调用Dispose 或使用using 语句。

    这是正确的方法:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 请注意,正如其他先生所说,在这种情况下使用许多 DataContext 可能会更好。但是,由于问题是如何保证在一个上下文中释放内存,ClearCache() 方法更接近答案。
      • 是的,使用或不使用多少datacontext取决于你的数据量,你可以学习如何处理这个,我从RobConery MVC Road系列学习...blog.wekeroad.com/category/mvc-storefront
      • 以下是调用 ClearCache() 的方法: context.GetType().InvokeMember( "ClearCache", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, context, null);
      • +1,虽然我发现我还需要一个绑定标志来告诉它调用方法:BindingFlags.InvokeMethod。
      • 我尝试了“DataContext.ObjectTrackingEnabled 为 false”,但是当我运行内存分析器时,它表明它已被处置但不能被 GCed。
      【解决方案3】:

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

      您的主要关注点似乎是创建和处理一堆 DataContext 对象。这就是 linq2sql 的设计方式。 DataContext 的生命周期很短。由于您要从数据库中提取大量数据,因此会有大量内存使用是有道理的。通过分块处理数据,您走在了正确的轨道上。

      不要害怕创建大量的 DataContexts。它们旨在以这种方式使用。

      【讨论】:

        【解决方案4】:

        谢谢大家 - 我会检查 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
           }
        }
        

        【讨论】:

          【解决方案5】:

          我刚刚遇到了类似的问题。就我而言,帮助将 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() 方法 - 无效

          【讨论】:

            猜你喜欢
            • 2010-12-22
            • 1970-01-01
            • 1970-01-01
            • 2020-05-13
            • 1970-01-01
            • 2012-10-22
            • 2015-08-27
            相关资源
            最近更新 更多