C# 在C中处理大文件时出现内存不足异常
我有一个WinC窗体应用程序,其中使用 OpenFileDialog允许用户选择要打开的文本文件。允许多选 一旦他们选择了文本文件,我就通过List.Add操作逐个打开文件,获取文本并将内容存储在列表变量中 我的问题发生在用户选择了大量的文本文件时,比如1264个文本文件,总大小高达750MB,程序无法处理它。它最多读取850个文件,然后给我一个内存不足异常。 在TaskManager中,发生这种情况时,应用程序的memoryprivate工作集大约为1.5GB。 我使用带有32GB ram的x64机器 我给出的代码可以读取文件:C# 在C中处理大文件时出现内存不足异常,c#,.net,winforms,visual-studio-2010,list,C#,.net,Winforms,Visual Studio 2010,List,我有一个WinC窗体应用程序,其中使用 OpenFileDialog允许用户选择要打开的文本文件。允许多选 一旦他们选择了文本文件,我就通过List.Add操作逐个打开文件,获取文本并将内容存储在列表变量中 我的问题发生在用户选择了大量的文本文件时,比如1264个文本文件,总大小高达750MB,程序无法处理它。它最多读取850个文件,然后给我一个内存不足异常。 在TaskManager中,发生这种情况时,应用程序的memoryprivate工作集大约为1.5GB。 我使用带有32GB ram的x
public static List<LoadData> LoadDataFromFile(string[] filenames)
{
List<LoadData> MasterData = new List<LoadData>();
lookingForJobs = new LookingForJobs(1,filenames.Length);
lookingForJobs.Show();
/*-------OUTER LOOP TO GO THROUGH ALL THE FILES-------*/
for (int index = 0; index < filenames.Length; index++)
{
string path = filenames[index];
/*----------INNER LOOP TO GO THROUGH THE CONTENTS OF EACH FILE------*/
foreach (string line in File.ReadAllLines(path))
{
string[] columns = line.Split('\t');
if (columns.Length == 9)
{
if (line.StartsWith("<")) /*-------IGNORING THE FIRST 8 LINES OF EACH LOG FILE CONTAINING THE LOGGER INFO---------*/
{
MasterData.Add(new LoadData
{
Event_Type = columns[0],
Timestamp = columns[1],
Log_Message = columns[2],
Category = columns[3],
User = columns[4],
Thread_ID = columns[5],
Error_Code = columns[6],
Application = columns[7],
Machine = columns[8]
});
}
}
}
lookingForJobs.SearchingForJobsProgress.PerformStep();
/*--------END OF INNER LOOP--------*/
}
lookingForJobs.Dispose();
/*-----------END OF OUTER LOOP-----*/
return MasterData;
}
编辑:
我知道我应该重新设计我的代码,这样就不会同时将所有文件读入对象。但是,我想知道列表对象或memoryprivate工作集的大小是否有任何限制。我在几篇文章中读到,有时当您达到1.5-1.6 GB时,会出现此类问题。使用File.ReadLines而不是File.ReadAllLines,因为第二行不必要地将所有文件加载到内存中,而您一次只需要一行:
使用ReadAllLines时,必须等待返回整个字符串数组,然后才能访问该数组。因此,当您处理非常大的文件时,ReadLines会更加高效
这可能会给您带来很大的内存改进
第二个想法是重新思考你是否真的需要如此大的数据存储在内存中。也许您可以只存储每个文件的文件路径,并根据需要读取它们。您的文件可能很小,但您正在构建的MasterData对象仍将存储它在内存中找到的所有数据 听起来您可能需要重新设计一些应用程序
您是否通过探查器运行了此操作?查看是否可以在整个程序过程中检查内存使用情况?您正在创建包含从文件中读取的大部分数据的对象。我认为类别、用户、错误代码、应用程序和机器的值将在许多记录中重复 您可以制作一个包含这些字符串值的字典。对于您读取的每个值,您将检查字典中是否已经存在相等的字符串,并使用该字符串,否则将其添加。这样,这些字符串在内存中只存在一次 字符串插入使用相同的原理,但如果您插入字符串,它们将保留在内存中,直到应用程序关闭。把它们放在字典里,你就可以在不再需要它们的时候把它们删除 榜样;编一本字典:
Dictionary<string, string> values = new Dictionary<string, string>();
string category = columns[3];
if (values.ContainsKey(category)) {
category = values[category];
} else {
values.Add(category, category);
}
当然,您只会在希望有大量重复值的值上使用此选项。您是在x64模式下构建应用程序吗?@Guffa添加内存直到它崩溃不一定是正确的修复方法,特别是当流式而非缓冲式方法非常简单时,请参见Konrad的回答您确定需要将所有数据同时存储在内存中吗@MarcGravel:由于每个文件处理后都会扔掉这些数据,我无法想象这会造成如此大的差异。@Simon,是的,也许我可以选择一种方法,在处理完数据后删除一些数据。我的主数据列表大小高达2564543个元素。这里有什么限制吗?有时候,一个看起来微不足道的改变是如此的有效。是的,我改变了它,同样的问题也发生了。单个文件不是很大,每个文件大小为650KB。因为每个文件处理后都会丢弃这些数据,所以不会有太大的区别。@KonradKokosa:必须为任一解决方案创建所有字符串对象,因此,与内存管理视图没有太大区别。至少有两种可能性:1使用x64,假设单个元素的数量不超过2^31;2将主数据写入文件,然后一次处理一个记录。这是一个我从未想到的有趣的优化。如果实现,将大大减少内存。谢谢