非常沉重的数据导致了foreach中的内存不足异常

问题描述:

首先,我得到了这个巨大的xml文件,它代表了设备收集的数据。我把它转换成一个对象。实际上,这个对象有一个对象列表。这些对象有三个字符串。该字符串是这样的:非常沉重的数据导致了foreach中的内存不足异常

0,12987; 0,45678; ...

这是某种形式的演出事宜安排这样的双列表。每个字符串中有1k个双打,所以每个对象有3k个,并且有一些类似3k对象的东西,只是为了让您了解一个典型案例。

当我读取数据时,我最常从objets中获得所有双打,并将它们添加到同一个列表中。我在foreach中创建了一个“包含三个双精度的对象”(每个字符串对应一个),我得到每个对象,然后将我的字符串分解为数组。之后,我循环将我的数组转换为“包含三个双打的对象”列表,并将其全部添加到一个列表中,以便我可以将其用于进一步的操作。

它会在结束之前导致内存不足异常。想法?与linq的东西将是最好的。

我有什么看起来是这样的:

+5

也许你可以发布你的代码;) – ken2k 2012-01-30 14:34:04

+1

段落可以使它更容易阅读。 :) – 2012-01-30 14:35:51

+1

3k * 3双打〜250k字节,不够OOM – 2012-01-30 14:39:17

让我们做一些数学。每个字符串1000个值*每个值8个字符(6位数加逗号和分号)*每个字符2个字节*每个对象3个字符串=每个对象48,000个字节。这本身并不是很多,即使有3000个对象,我们仍然只谈论大约150MB的RAM。对现代系统来说,这仍然没有什么。转换为double数组甚至更少,因为每个值只有8个字节,而不是16个。字符串也是引用类型,所以在字符串版本中也会有开销。重要的是,不管你如何使用它,你仍然远远没有达到85,000字节的阈值,因为它们被困在大对象堆上,这是OutOfMemoryException的正常来源。

没有代码很难跟着你在做什么,但我有几个不同的猜测:

  1. 许多在你的字符串值都在5位数以上,这样你穿越魔术毕竟85,000字节的门槛,你的对象最终在垃圾收集器中的大对象堆。因此,它们不会被收集,并且随着您继续处理对象,您很快就会将自己从地址空间(而不是真实的RAM)中移出。
  2. 你正在提取你的双打,你反复重建字符串的方式。这会在垃圾回收器上产生很多内存压力,因为它会一遍又一遍地重新创建字符串。
  3. 如果这是一个长时间运行的程序,其中每个字符串中的项目大小和数量可能会有很大差异,那么随着时间的推移,您可能会遇到一些大型值列表, 85,000字节的标记。

无论哪种方式,你想要在这里做的是停止列表方面的事情,并开始思考序列。请尝试IEnumerable<string>IEnumerable<double>,而不是List<string>List<double>。为您的字符串编写一个解析器,该解析器使用yield关键字创建一个迭代器块,通过迭代字符而不更改字符串,该迭代器块将一次一个地从字符串中提取双精度值。这会更好地执行方式,并且可能会解决您的内存问题。

+0

我终于决定审查循环。其中有太多的操作。现在它运行良好,但我不得不重新考虑整个事情,所以最少的数据被转化了。我没有完全使用你的解决方案,但很明显,通过阅读我的方式出了问题,非常感谢。 – Fjodr 2012-01-30 20:03:10