我有一个C#winforms应用程序,其中我使用了一个 OpenFileDialog让用户选择要打开的文本文件。(允许多项选择) 一旦他们选择了文本文件,我将逐个打开文件,获取文本并使用List.Add()操作将内容存储在List变量中。
当用户选择异常大量的文本文件(如1264个文本文件,总大小高达750MB)时,我的问题就出现了,程序无法处理它。它读取了大约850个文件然后给我一个内存不足的例外。 在任务管理器中,当发生这种情况时,我的应用程序的内存(私有工作集)大约为1.5GB。 我使用带有32GB内存的x64机器。
我正在提供读取文件的代码:
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;
}
编辑: 我知道我应该重新设计我的代码,以便不是所有的文件都被立即读入对象。但是,我想知道列表对象或内存(私有工作集)的大小是否有任何限制。我在一些文章中读到,当你达到1.5-1.6 GB时会发生这类问题。
答案 0 :(得分:7)
使用File.ReadLines
代替File.ReadAllLines
,因为第二个不必要地将所有文件加载到内存中,而您一次只需要一行。 MSDN says:
使用ReadAllLines时,必须等待返回整个字符串数组才能访问该数组。因此,当您使用非常大的文件时,ReadLines可以更高效。
这可能会给你带来很大的记忆力提升。
第二个想法是重新考虑一下你是否真的需要存储在内存中的如此大的数据。也许你可以只将文件路径存储到每个文件中并按需读取它们。
答案 1 :(得分:4)
您的文件可能很小,但您正在构建的MasterData对象仍将存储它在内存中找到的所有数据...
听起来你可能需要重新设计一些应用程序......
您是否通过分析器运行了这个 - 看看您是否可以在整个程序过程中检查内存使用情况?
答案 2 :(得分:2)
您正在创建包含从文件中读取的大部分数据的对象。我认为类别,用户,错误代码,应用程序和机器的值将重复用于大量记录。
您可以创建包含这些字符串值的字典。对于您阅读的每个值,您将检查字典中是否已存在相等的字符串并使用该字符串,否则添加它。这样那些字符串只会在内存中存在一次。
字符串实习使用相同的原则,但是你实际上它们将保留在内存中的字符串直到应用程序关闭。通过将它们放入字典中,您可以在不再需要它们时将其删除。
实施例;做一本字典:
Dictionary<string, string> values = new Dictionary<string, string>();
获取值并在字典中使用/注册一个值:
string category = columns[3];
if (values.ContainsKey(category)) {
category = values[category];
} else {
values.Add(category, category);
}
您当然只会在期望有大量重复值的值上使用它。