2

我有一个程序,它将从数据库中读取 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 后会遇到“内存不足”异常,并且非常一致。而且我注意到循环时内存使用量不断增加。我什至强制垃圾收集也无法回收任何内存。我与 LINQ 的交互是否有任何问题,导致内存被阻塞而不被释放。任何帮助都感激不尽。

4

3 回答 3

1

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

更好的是,将其重写为单个 SQL 语句会为您省去所有麻烦。

重新创建上下文在 CPU 方面是相当繁重的,如果您只需要一个连接,正如您在上面的示例中所示,那么多次创建它就是浪费资源。

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

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

最后你想看看批量插入。

于 2012-05-08T08:07:19.310 回答
1

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

于 2015-05-13T14:39:47.127 回答
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 数据库中创建一个存储过程并执行它。

于 2012-05-08T09:55:14.910 回答