我的问题是,当用户打开大于300MB的日志文件时,应用程序会抛出内存不足异常。
该应用程序首先将所有日志行加载到一个字符串数组中,然后循环遍历日志行,将日志条目对象添加到列表中。
var allLogLines = File.ReadAllLines(logPath).ToList();
var nonNullLogLines = allLogLines.Where(l => !string.IsNullOrEmpty(l));
this.ParseLogEntries(nonNullLogLines.ToArray());
这个初始步骤(将日志数据加载到字符串数组中)在任务管理器中使用了约1GB的内存。
internal override void ParseLogEntries(string[] logLines)
{
this.LogEntries = new List<LogEntry>();
this.LogLinesCount = logLines.Count();
for (int i = 0; i < this.LogLinesCount; i++)
{
int entryStart = this.FindMessageCompartment(logLines, i);
int entryEnd = this.FindMessageCompartment(logLines, entryStart + 1);
int entryLength = (entryEnd - entryStart) + 1;
if (entryStart + entryLength > this.LogLinesCount)
{
entryLength = this.LogLinesCount - entryStart;
}
var logSection = new string[entryLength];
Array.Copy(logLines, entryStart, logSection, 0, entryLength);
Array.Clear(logLines, i, entryLength - 1);
this.AddLogEntry(logSection);
i = (entryEnd - 1);
}
}
AddLogEntry方法向列表(LogEntries)添加日志条目。在for循环中,成功解析了约50%的日志文件,然后发生了内存不足异常。此时任务管理器报告该应用程序使用了约1.3GB的内存。
如上所述,我已经添加了Array.Clear以清空已成功解析的日志数据部分,因此我期望随着对象被添加到集合中,大型日志数据数组使用的内存(一开始为1GB)会稳步减少,但事实并非如此。事实上,即使我定期添加GC Collect,这行代码也对内存使用量没有任何影响。
阅读了关于LOH的相关文章后,我认为这是因为堆没有在将大数组的某些部分置为空时进行压缩,因此它始终使用相同的1GB内存,尽管其内容不同。
是否有任何方法可以减少在解析数据时所占用的内存量,或者可能进行重新设计以更好地利用内存?对我来说,一个300MB的文本文件,当放入一个字符串数组中,消耗了1GB的内存,这似乎很奇怪?
谢谢。
FindMessageCompartment
?同时不要使用数组,使用通用的List<string>
。 - sll