我试图在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事件。
答案 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)
}
}