1

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

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

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循环的每次迭代都是如此。

有没有人遇到过这个?我怀疑直接调用存储过程或进行插入将避免这种泄漏,但我想在尝试其他方法之前了解这一点。到底是怎么回事?

更新

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

4

2 回答 2

0

你在哪个操作系统上运行这个?您的问题可能与 Linq2Sql 无关,而是与操作系统如何管理大内存分配有关。例如,Windows Server 2008 在管理内存中的大对象方面比 XP 好得多。我遇到过处理大文件的代码在 XP 上泄漏但在 Win 2008 服务器上运行良好的情况。

高温高压

于 2009-11-20T00:01:58.550 回答
0

我不完全明白为什么,但是制作迭代变量的副本修复了它。据我所知,LinqToSql 以某种方式在每个 Document 中制作了 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)
    }
}
于 2009-11-20T16:25:22.277 回答