我有一个非常大的文本文件要解析(~2GB)。由于各种原因,我必须逐行处理文件。我通过将文本文件加载到内存(我正在运行解析器的服务器有足够的内存)来做到这一点var records = Regex.Split(File.ReadAllText(dumpPath, Encoding.Default), @"my regex here").Where(s => !string.IsNullOrEmpty(s));
。这消耗的 RAM 相当于文本文件的大小加上几 MB 的IEnumerable
开销。到目前为止,一切都很好。然后我与foreach (var recordsd in records) {...}
有趣的部分来了。我在 foreach 循环中做了很多字符串操作和正则表达式。然后程序很快就会用 System.OutOfMemoryException 轰炸,即使我在 foreach 循环中从未使用超过几 kB。我使用我选择的分析器(ANTS 内存分析器)制作了一些内存快照,在堆上看到了数百万个第 2 代字符串对象,消耗了所有可用内存。
看到这一点,我 -就像一个测试一样- 在每次 foreach 迭代结束时都包含 a GC.Collect();
,瞧,问题解决了,不再出现内存不足的异常(因为永久垃圾收集,程序现在运行得非常缓慢)。唯一消耗的内存是实际文件的大小。
现在我无法解释为什么会发生这种情况以及如何防止它。据我了解,当变量超出范围并且没有更多(活动)引用时,应该将其标记为垃圾收集,对吗?
另一方面,我试图在一台非常庞大的机器(64GB RAM)上运行该程序。程序成功完成,但在关闭之前从未释放一个字节的内存。为什么?如果没有更多对对象的引用加上如果对象超出范围,为什么永远不会释放内存?