我有一个程序,它将从数据库中读取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的交互是否有任何问题,从而导致内存滞留而不被释放。任何帮助将不胜感激。
答案 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数据库中创建存储过程并执行该过程。