导致内存不足异常的对象太多

时间:2015-09-30 15:10:35

标签: c# asp.net .net

快速了解我的情况: 我按计划得到文本文件,按字符数分割,我正在开发一个应用程序,根据其解析的文件将每一行拆分为一个模型列表。例如。 300行的Persons Text文件将创建自定义模型“Person”的列表。列表中的每个项目都是文件中的一行。它是通过以下方式实现的:

    private static List<Person> InitializePeople(DataManager dm, string filePath)
    {
        List<Person> people= new List<Person>();
            //Get lines from file to loop through
            foreach (var line in dm.GetDataLinesFromFile(filePath).ToList())
            {
               Person person = new Person();
               //This splits out the character counted split line 
               //into the models format and adds it to a list
               people.Add((Person)dm.GetFormattedData(person, new FormatManger(), line));
            }
        return people;
     }

这个工作正常,直到我得到一个数百万行的文件。正如你所看到的那样,我在循环中提交了一个厚颜无耻的NONO,我每次循环时都会实例化一个新对象。这是我相信我的问题所在,当实例化对象的奇迹时,它开​​始为内存而苦苦挣扎。这样做的更好方法是什么?还有一些更有记忆效果的方式吗?任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:3)

不要具体化数据(即避免ToList()ToArray()等)仅与IEnumerable一起使用。

首先,检查dm.GetFormattedData实现它应该是

  public IEnumerable<String> GetDataLinesFromFile(filePath) {
    // Check that neither ReadAllLines nor ReadAllText is there
    // Check absence of ToList() and ToArray() as well
    return File
      .ReadLines(filePath) // the only possible way of reading file
      .Select(...) // possible, but not necessary part
      .Where(...); // possible, but not necessary part
  }

然后将InitializePeople重新设计成类似的东西:

   // Note IEnumerable<Person> instead of List<Person>
   public static IEnumerable<Person> InitializePeople(DataManager dm, string filePath) {
    //TODO: what's "nmy"?
    //TODO: do you really want new FormatManger() for each People instance?
    return GetDataLinesFromFile(filePath)
      .Select(line => (Person)dm.GetFormattedData(nmy, new FormatManger(), line));  
  } 

因此,在 Linq 的帮助下,您可以拥有很多灵活性,例如

  File.WriteAllLines(@"C:\MyFile.txt", InitializePeople(dm, @"C:\People.txt")
   .Where(people => people.LastName == "Smith")
   .Select(people => String.Format("{0} is {1} years old", people.FirstName, people.Age));

答案 1 :(得分:1)

People列表太大而无法保留在内存中。我建议在处理下一个块之前以块的形式处理每个块。 如果您更改方法签名以接受块大小和位置private static List<Person> InitializePeople(DataManager dm, string filePath, int chunkSize, out int position),则可以实现此目的。这样,您就不必阅读整个文件,只需跳到某一行,然后读取所需的记录数量。

伪代码看起来像:

var position = 0
var people = []
while (count (people = InitializePeople(dataManager, file, 250, out position) > 0)
    do something with people
    position += count people