lig*_*txx 2 c# garbage-collection memory-management out-of-memory
我有一个非常大的文本文件来解析(~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循环中做了很多字符串操作和regex-ing.然后程序很快就会发生System.OutOfMemoryException炸弹,即使我在foreach循环中从不使用超过几KB的程序.我使用我选择的探测器(ANTS内存探查器)制作了一些内存快照,在堆上看到数百万个第2代字符串对象,消耗了所有可用内存.
看到这一点,我 - 就像一个测试 - 包括GC.Collect();在每个foreach迭代结束时,瞧,问题解决了,没有更多的内存异常(当然,因为永久垃圾收集,程序现在运行得非常慢).消耗的唯一内存是实际文件的大小.
现在我无法解释为什么会发生这种情况以及如何防止它.根据我的理解,变量超出范围并且没有更多(活动)引用的那一刻应标记为垃圾收集,对吧?
另一方面,我试图在一台非常庞大的机器(64GB RAM)上运行该程序.程序成功完成但在关闭之前从未释放过单个字节的内存.为什么?如果没有更多对象的引用加上如果对象超出范围,为什么内存永远不会释放?
现在我无法解释为什么会发生这种情况以及如何防止它.根据我的理解,变量超出范围并且没有更多(活动)引用的那一刻应标记为垃圾收集,对吧?
没有.没有为垃圾收集"标记"的事情,并且变量不是垃圾收集:对象是.并且在下一次GC查看gen2时,已经在gen2中的对象将不会被垃圾收集,这是相对罕见的.
由于各种原因,我必须按行处理文件.
然后是你的答案:File.ReadLines如果你使用的是.NET 4,请使用等效的(如果你不是,那就很容易).那么你一次不需要内存中的整个文件 - 只需一行.你的内存使用量应该绝对直线下降.(请注意,那是ReadLines,不是 ReadAllLines -后者将读取整个文件转换成字符串数组,这是不是你想要的.)
另一方面,我试图在一台非常庞大的机器(64GB RAM)上运行该程序.程序成功完成但在关闭之前从未释放过单个字节的内存.为什么?
如果你在谈论进程从操作系统获取的内存,我不相信 CLR会释放内存.我假设它采用的方法是,如果你曾经使用过那么多内存,你可能会再次使用那么多.
| 归档时间: |
|
| 查看次数: |
336 次 |
| 最近记录: |