我有一些非常大的文件,每个500MB++
大小,包含整数值(实际上它有点复杂),我正在循环中读取这些文件并计算所有文件的最大值。由于某种原因,内存在处理过程中不断增长,看起来GC似乎永远不会释放由lines
之前的实例获取的内存。
我无法流式传输数据,必须为每个文件使用GetFileLines
。如果为一个文件存储lines
所需的实际内存量为500MB
,为什么在处理10个文件后会使用5GB
RAM
个 int max = int.MinValue;
for (int i = 0; i < 10; i++)
{
IEnumerable<string> lines = Db.GetFileLines(i);
max = Math.Max(max, lines.Max(t=>int.Parse(t)));
}
?最终,在15个文件后,它会因内存不足而崩溃。
计算:
public static List<string> GetFileLines(int i)
{
string path = GetPath(i);
//
List<string> lines = new List<string>();
string line;
using (StreamReader reader = File.OpenText(path))
{
while ((line = reader.ReadLine()) != null)
{
lines.Add(line);
}
reader.Close();
reader.Dispose(); // should I bother?
}
return lines;
}
GetFileLines代码:
{{1}}
答案 0 :(得分:5)
对于非常大的文件,方法ReadLines
最适合,因为它是延迟执行,它不会在内存中加载所有行并且易于使用:
Math.Max(max, File.ReadLines(path).Max(line => int.Parse(line)));
更多信息:
http://msdn.microsoft.com/en-us/library/dd383503.aspx
修改强>
这就是ReadLines
在幕后实现的方式:
public static IEnumerable<string> ReadLines(string fileName)
{
string line;
using (var reader = File.OpenText(fileName))
{
while ((line = reader.ReadLine()) != null)
yield return line;
}
}
此外,当您有多个文件时,建议使用并行处理来提高性能
答案 1 :(得分:4)
您可能会崩溃,因为在完成处理后,您将在内存中保留对已解析结果的引用(您显示的代码不会执行此操作,但是您运行的代码是否相同?)。 StreamReader
中存在这样的错误的可能性极小。
您确定必须立即读取内存中的所有文件吗?可能使用可枚举的行序列IEnumerable<string>
而不是在前面加载List<string>
。至少在这段代码中没有任何东西禁止这样做。
最后,Close
和Dispose
来电是多余的; using
会自动处理此问题。
答案 2 :(得分:1)
为什么不实现如下:
int max = Int32.MinValue;
using(var reader = File.OpenText(path))
{
while ((line = reader.ReadLine()) != null)
{
int current;
if (Int32.TryParse(line, out current))
max = Math.Max(max, current);
}
}
答案 3 :(得分:0)
您正在将整个文件读入内存(列表行)
我猜你一次只能读一行并保持最高数字?
它会为你节省很多内存。
答案 4 :(得分:0)
您似乎总是将整个文件加载到内存中。同时,您还要为文件的每一行创建托管对象(List)。
没有理由让你的内存使用量增长。
请发布其余的代码,我怀疑你是在某个地方参考这个正在使用的列表,因此它没有被处置。
答案 5 :(得分:0)
好吧,如果你想要一个可以一次阅读整个文件的解决方案,因为你肯定你需要获得性能提升,那么让我们这样做,这样就可以了没有记忆问题。
public static int GetMaxForFile(int i)
{
string path = GetPath(i);
var lines = new List<string>(File.ReadAllLines(path));
// you MUST perform all of your processing here ... you have to let go
// of the List<string> variable ...
int max = Math.Max(max, lines.Max(t=>int.Parse(t)));
// this may be redundant, but it will cause GC to clean up immediately
lines.Clear();
lines = null;
return max;
}