LinqToSql InsertOnSubmit内存泄漏?

时间:2009-11-19 22:44:53

标签: c# linq-to-sql memory-leaks out-of-memory

我试图在C#应用程序中隔离“内存泄漏”的来源。此应用程序使用SQL Server中的image列类型将大量可能较大的文件复制到数据库中的记录中。我正在使用LinqToSql和相关对象进行所有数据库访问。

主循环遍历文件和插入列表。删除了很多样板和错误处理之后,它看起来像这样:

foreach (Document doc in ImportDocs) {
    using (var dc = new DocumentClassesDataContext(connection)) {
        byte[] contents = File.ReadAllBytes(doc.FileName);

        DocumentSubmission submission = new DocumentSubmission() {
            Content = contents,
            // other fields
        };

        dc.DocumentSubmissions.InsertOnSubmit(submission);  // (A)
        dc.SubmitChanges();                                 // (B)
    }
}

在整个输入上运行此程序会导致最终OutOfMemoryException。 CLR Profiler揭示了99%的堆由与文件大小相对应的大byte[]个对象组成。

如果我对A行和B行都进行评论,那么这种泄漏就会消失。如果我只取消注释A行,那么泄漏就会回来。我不明白这是如何可能的,因为dc被置于循环的每次迭代中。

之前有没有遇到过这个?我怀疑直接调用存储过程或插入将避免这种泄漏,但我想在尝试其他事情之前理解这一点。发生了什么事?

更新

在(B)行之后包括GC.Collect();似乎对任何情况都没有重大改变。这并不让我感到惊讶,因为CLR Profiler在没有明确引发它们的情况下显示了大量的GC事件。

2 个答案:

答案 0 :(得分:0)

您在运行此操作系统?您的问题可能与Linq2Sql无关,而是与操作系统如何管理大内存分配有关。例如,Windows Server 2008在管理内存中的大型对象方面要比XP好得多。我有一些实例,使用大文件的代码在XP上泄漏但在Win 2008服务器上运行正常。

HTH

答案 1 :(得分:0)

我不完全理解为什么,但是制作一个迭代变量的副本来修复它。就像我所知,LinqToSql以某种方式在每个文档中制作了DocumentSubmission的副本。

foreach (Document doc in ImportDocs) {
    // make copy of doc that lives inside loop scope
    Document copydoc = new Document() {
        field1 = doc.field1,
        field2 = doc.field2,
        // complete copy
    };

    using (var dc = new DocumentClassesDataContext(connection)) {
        byte[] contents = File.ReadAllBytes(copydoc.FileName);

        DocumentSubmission submission = new DocumentSubmission() {
            Content = contents,
            // other fields
        };

        dc.DocumentSubmissions.InsertOnSubmit(submission);  // (A)
        dc.SubmitChanges();                                 // (B)
    }
}