限制RAM的使用(C# .NET)

4

有大约100Mb的巨型文件。

我想将它们加载到内存(RAM)中,进行处理并保存在某个地方。

同时,我希望存在内存使用限制。例如,100Mb,以便我的应用程序不会超出这个内存限制。如果超出限制,则对文件进行分段处理。

我的理解是:

var line = file.ReadLine();
var allowed = true;

while( allowed && line != null ) 
{
   var newObject = new SomeObject( line );
   list.add( newObject );

   // Checking the memory
   allowed = CheckUsedMemory(); 

   line = file.ReadLine()
} 

如何限制RAM的使用? 如何实现CheckUsedMemory方法? 谢谢。
更新:
感谢大家的好建议。

100MB的内存使用并不算很大......一个巨大的文件应该是以GB而不是MB来衡量... - Mitch Wheat
4
为什么需要在内存中处理文件?我问这个问题是因为如果不知道为什么逐行处理不可行,就无法讨论是否可以加载和处理文件块。 - Ekkehard.Horner
每当“allowed”为false时,该代码将会漏掉一行。 - mgronber
2
我甚至会添加另一个问题:如果你有一行长达1GB的单行呢?或者2GB?或3GB?如果你在进行“防御性编程”,那么你必须编写自己的ReadLine(可能是分块版本,每次读取4k,按行结束符拆分,返回拆分但不包括最后一个的部分,并将最后一个保存以合并到下一个块的第一行) - xanatos
上次我有一个120MB的原始格式[CSV]数据库。当我在浏览器中打开它们时,所有内容都无法正常工作。之后,我恢复了我的系统,因为此后我的系统中的每个应用程序都会崩溃,无论大小。 - user605334
5个回答

6
你可以尝试以下方法:
long usedMemory = GC.GetTotalMemory(true);

或者
long usedMemory = GC.GetTotalMemory(false);

第一步将强制进行垃圾回收(清理)内存,因此速度较慢(毫秒级别)。

然后阅读以下内容以查看您的计算机拥有多少内存:

如何获取计算机的总内存量?

请记住,如果您作为32位应用程序运行,则无法使用所有内存,并且其他进程可能正在使用该内存!


6
首先,感谢您关注内存消耗。如果更多的程序员都能这样考虑就好了。
其次,我觉得没必要限制内存:也许用户想让您的应用程序尽可能快地运行,并愿意烧掉8000兆内存以获得5%更快的结果。让他们自己决定吧。 :)
但是,如果您强制限制应用程序所需的内存量,可能会极大地增加处理时间,因为此过程中可能会强制进行更多的磁盘访问。如果某人正在运行内存受限的系统,则可能已经有交换的磁盘流量 - 如果您在实际完成之前人为地释放内存,那么您只会进一步增加磁盘IO,妨碍交换。让操作系统来处理这种情况吧。
最后,您在这里编写的访问模式(顺序、逐行)非常常见,毫无疑问,.NET设计人员已经付出了巨大的努力,以使该模式的内存使用率降至最低。将对象分批添加到内部树中是一个好主意,但很少有应用程序真正从中受益。(归并排序是一个极好的应用程序,它从部分处理中受益匪浅。)
根据您对对象列表的使用方式,您可能无法一次性处理整个列表。或者,将其拆分后可能会有很大的好处。(如果Map Reduce能够很好地描述您的数据处理问题,那么也许您会从中受益。)
无论如何,我会有点谨慎地使用“内存”作为决定何时分解处理的基准:我宁愿使用“1000行输入”、“十级嵌套”、“运行机器工具五分钟”或其他基于输入而非内存消耗的标准来决定。

2
正常的程序是不将所有内容加载到内存中,而是分块读取文件、处理并保存。如果由于某些原因必须将所有内容保存在RAM中(例如排序),那么你可能需要投资更多的RAM。
这是你所使用的算法的问题,因此问题应该是如何在不使用太多内存的情况下解决特定任务的问题。 GC.GetTotalMemory() 将告诉你正在使用多少内存。
现在100MB的RAM不算很多。将其读入内存、处理并重新写回磁盘可能会非常快速。记住你无论如何都无法避免从磁盘到内存再到磁盘的复制。使用StringBuilder(而不是String)来保存它不一定会给应用程序增加太多开销。一次性写入100MB肯定比逐行写入要快得多。

1

你实际上无法限制内存使用量。你只能限制保留的内存量。其余内存是否释放取决于垃圾回收器。

因此,我建议您只关注当前缓冲区中正在缓冲的行数(或更好的是字符数),然后再对它们进行处理。

在评论中,有人建议您逐行读取文件。这是一个非常好的建议,假设您能够一次处理单个行。操作系统无论如何都会缓存文件,因此不会损失任何性能。


1

看起来你想逐行处理文件,但是了解一下 .NET 4 ,你可以使用内存映射文件,这能让你稀疏地访问大型文件


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接