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 方法?谢谢你。

UPD

谢谢大家的好建议。

4

5 回答 5

6

您可以尝试:

long usedMemory = GC.GetTotalMemory(true);

或者

long usedMemory = GC.GetTotalMemory(false);

第一个将强制对内存进行垃圾收集(清理),因此速度较慢(毫秒)

然后阅读此内容以查看您的机器有多少内存:

您如何获得计算机的 RAM 总量?

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

于 2011-02-20T10:33:32.467 回答
5

首先,感谢您了解您的内存消耗。如果只有更多的程序员如此体贴..

其次,我不会打扰:也许用户希望您的应用程序尽可能快地运行,并且愿意消耗 8000 兆内存以将结果提高 5%。让他们。:)

但是,人为限制应用程序占用的内存量可能会大大增加处理时间,如果您在进程中强制进行更多磁盘访问。如果有人在内存受限的系统上运行,他们很可能已经有用于交换的磁盘流量——如果你在真正完成之前人为地转储内存,你只会进一步增加磁盘 IO,进入交换的方式。让操作系统处理这种情况。

最后,您在此处编写的访问模式(顺序、一次一行)非常常见,毫无疑问,.NET 设计人员已投入大量精力将这种模式的内存使用量降至最低。将对象分段添加到您的内部树是一个好主意,但很少有应用程序能真正从中受益。(合并排序是一种出色的应用程序,它从部分处理中受益匪浅。)

根据您对完成的对象列表所做的工作,您可能无法同时处理整个列表。或者,您可能会从拆开它中受益匪浅。(如果Map Reduce很好地描述了您的数据处理问题,那么您可能会从拆分中受益。)

无论如何,我对使用“内存”作为决定何时拆分处理的基准有点谨慎:我宁愿使用“1000 行输入”或“十级嵌套”或“运行机床”五分钟”或基于输入的内容,而不是内存消耗的次要影响。

于 2011-02-20T10:57:38.250 回答
2

正常的过程是不将所有内容加载到内存中,而是分块读取文件,处理并保存。如果您出于某种原因必须将所有内容保存在 RAM 中(例如用于排序),那么您很可能不得不投资更多的 RAM。

这是您使用的算法的问题,因此问题应该是关于如何在不使用太多内存的情况下解决特定任务。

GC.GetTotalMemory()会告诉你你正在使用多少内存。

今天 100MB RAM 并不多。将它读入内存、处理它并将其放回磁盘可以非常快。请记住,无论如何您都无法避免将其从磁盘复制到内存然后再复制回磁盘。使用 StringBuilder(不是 String)来保存它不一定会给应用程序增加太多开销。在一次操作中写入 100MB 肯定比一次写入一行要快。

于 2011-02-20T11:03:22.590 回答
1

您不能真正限制内存使用量。您只能限制您保留的内存量。其余内存是否被释放取决于垃圾收集器。

因此,我建议您在处理它们之前只对当前正在缓冲的行数(或者最好是字符数)感兴趣。

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

于 2011-02-20T10:41:12.323 回答
1

看起来您想逐行处理文件,但知道使用 .NET 4,您可以使用内存映射文件可能会有所帮助,这使您可以稀疏地访问大文件

于 2011-02-20T10:47:39.893 回答