【发布时间】:2012-03-10 01:22:08
【问题描述】:
我经常(每 30-60 分钟)在我的 Windows 服务中收到 System.OutOfMemoryException。该服务的工作是遍历包含数据文件的 6 个目录,服务会将这些数据文件清洗成通用的 XML 数据格式。
这 6 个文件夹每个包含 5-10.000 个文件,因此文件总数约为 45.000 个,并且在当天添加了新文件。每天增加大约 1-2000 个新文件。文件大小在 4KB 到 500KB 之间。
每个数据文件都通过XElement对象清洗成通用的XML数据格式。
我在服务上使用了 RedGates ANTS Memory Profiler,使用最多内存的对象是字符串(大约 90.000.000 字节)和 XElement(大约 51.000.000 字节)。
在内存分析器中,当我跟踪使用字符串对象的内容时,我可以看到大部分(93%)是 XElement 对象在使用字符串对象。
服务器有 6 个 CPU 和 6GB 内存,所以我不明白为什么我会收到 OutOfMemoryException。如果我查看进程中的 Windows 服务,它的最大 RAM 使用量为 1.2GB。
我读到.NET 垃圾收集器不会清除字符串对象,因为字符串对象存储在实习表中。这可能是错误,如果是我该怎么办?
下面的代码显示了我如何循环文件。如您所见,我也尝试一次获取 20 个文件。这只会将 OutOfMemoryException 推送几个小时,因此服务将运行 4-5 小时而不是 30-60 分钟。
为什么会出现 OutOfMemoryException?
private static void CheckExistingImportFiles(object sender, System.Timers.ElapsedEventArgs e)
{
CheckTimer.Stop();
var dir = Directory.GetFiles(RawDataDirectory.FullName, "*.*", SearchOption.AllDirectories);
List<ManualResetEvent> doneEvents = new List<ManualResetEvent>();
int i = 0;
//int doNumberOfFiles = 20;
foreach (string existingFile in Directory.GetFiles(RawDataDirectory.FullName, "*.*", SearchOption.AllDirectories))
{
if (existingFile.EndsWith("ignored") || existingFile.EndsWith("error") || existingFile.EndsWith("importing"))
{
//if (DateTime.UtcNow.Subtract(File.GetCreationTimeUtc(existingFile)).TotalDays > 5)
// File.Delete(existingFile);
//continue;
}
StringBuilder fullFileName = new StringBuilder().Append(existingFile);
if (!fullFileName.ToString().ToLower().EndsWith("error") && !fullFileName.ToString().ToLower().EndsWith("ignored") && !fullFileName.ToString().ToLower().EndsWith("importing"))
{
File.Move(fullFileName.ToString(), fullFileName + ".importing");
fullFileName = fullFileName.Append(".importing");
ImportFileJob newJob = new ImportFileJob(fullFileName.ToString());
doneEvents.Add(new ManualResetEvent(false));
ThreadPool.QueueUserWorkItem(newJob.Run, doneEvents.ElementAt(i));
i++;
}
//if (i > doNumberOfFiles)
//{
// i = 0;
// doNumberOfFiles = 20;
// break;
//}
}
i = 0;
WaitHandle.WaitAll(doneEvents.ToArray());
CheckTimer.Start();
}
【问题讨论】:
-
ImportFileJob做什么?它是如何实现的? -
您对
StringBuilder的使用是多余的。 IOW 没有任何好处。 -
ImportFileJob 获取数据文件并使用 xlst 样式表将数据文件转换为通用 XML 数据文件。
-
我在应用程序中使用了 List
,导致服务在 3-5 分钟后出现内存不足异常。 ANTS 内存分析器告诉我,原因是 List 。用 List 改变它解决了这个问题。但是异常不断出现,只是没有那么快,所以我尝试用 StringBuilder 替换所有字符串,因为我读到字符串对象不是由 .NET GC 收集的。 -
能否也显示 ImportJob 的代码?此方法中没有 XDocument,所以我猜测任何导致 51MB 的 XDocument 价值的问题都隐藏在那里。
标签: c# .net out-of-memory heap-memory