LINQ to SQL的内存泄漏

时间:2012-05-08 07:57:28

标签: c# .net linq-to-sql

我有一个程序,它将从数据库中读取100万条记录,并在经过一些处理后将记录插入另一个表中。因此,程序调用DAO API来获取100万条记录并在内存中循环它们。插入也使用DAO API来执行插入。每个DAO API部分都实现为

    public static void Main(string[] args)
    {
        List<TableA> tableAs = GetTableAs();
        TableB tableB = null;
        foreach (var tableA in tableAs) {
           tableB.id = tableA.id;
           // ...
           // here I copy/modify records from table A
           // ...
           InsertTableB(tableB);
        } 
    }

    public static List<TableA> GetTableAs()
    {
        using (var ctx = new TableDataContext())
        {
            var entities = from e in ctx.tableAs
                           select e;
            return new List<tableA>(entities);
        }
    }

    public static void InsertTableB(TableB tableB)
    {
        using (var ctx = new TableDataContext())
        {
            ctx.tableBs.InsertOnSubmit(tableB);
            ctx.SubmitChanges();
        }
    }

我的程序在500k插入后会遇到“Out of memory”异常并且非常一致。我注意到循环时内存使用量不断增加。我甚至强制垃圾收集也无法回收任何内存。我与LINQ的交互是否有任何问题,从而导致内存滞留而不被释放。任何帮助将不胜感激。

3 个答案:

答案 0 :(得分:1)

首先,我认为你应该重新考虑编写代码的方式,现在它是疯狂的低效率,例如你每次都重新创建上下文,为什么不保留一个上下文?

更好的是,将它重写为单个SQL语句可以省去所有麻烦。

重新创建上下文是非常重要的CPU,如果你只需要一个连接,正如你在上面的例子中所示,那么创建它一次就浪费了资源。

其次LINQ to SQL在您创建,编辑,修改的每个对象上都有更改跟踪,因此它知道要处理的对象。并且可能是你记忆问题的根源。

所以我建议使用ObjectTrackingEnabled = false,看看会发生什么。

最后你想看看Bulk Inserting。

答案 1 :(得分:1)

当尝试使用linq2sql插入超过3000000行时,我遇到了同样的问题。在700k的插入之后出现OutOfMemoryException。最后,我只是处理以前的DataContext并在100k之后创建新的,甚至不关闭跟踪。

答案 2 :(得分:0)

问题很可能不在于.NET CLR中的内存泄漏,而在于上面的LINQ to SQL代码需要执行的大量内存。

请先参阅此MSDN博客帖子: http://blogs.msdn.com/b/tom/archive/2008/04/10/chat-question-memory-limits-for-32-bit-and-64-bit-processes.aspx

由于我没有任何硬件规格,我将假设内存限制为2800MB,如上文所述。

1,000,000 records <= 2800MB
1,000,000 records <= 23,488,102,400 bits
1 record <= 23488.1024 bits
1 record <= 2.8672KB

理论上,这意味着从表A复制到内存中的每条记录不应超过2.8672KB。

然而,由于CLR涉及的其他开销,实际值通常较低,这反映在从表A深度复制500,000条记录然后插入表B后抛出的OutOfMemoryException中。

当然,有一些方法可以增加可以保存在内存中的记录数量,就像其他海报所建议的那样,但问题很可能会随着表A中记录数量的增加再次出现。

可行的替代方法可能是在底层SQL Server数据库中创建存储过程并执行该过程。