关于MemoryStream编写的OutOfMemoryException

我有一个小样本应用程序我正在努力尝试获得一些新的.Net 4.0 Parallel Extensions(它们非常好)。 我遇到了OutOfMemoryException的(可能真的很愚蠢)问题。 我想要将这个样本插入读取一些数据和大量文件的主要应用程序,对它们进行一些处理,然后将它们写出来。 我遇到了一些问题,文件变得越来越大(可能是GB),并担心内存,所以我想并行化导致我走这条道路的事情。

现在下面的代码在较小的文件上得到了OOME,我想我只是遗漏了一些东西。 它将读入10-15个文件并很好地将它们写在parellel中,但随后它会在下一个文件中窒息。 看起来它的读写速度约为650MB。 第二组眼睛将不胜感激。

我正在从FileStream读取MemorySteam,因为这是主应用程序所需要的,我只是想在某种程度上复制它。 它从所有类型的地方读取数据和文件,并作为MemoryStreams处理它们。

这是使用.Net 4.0 Beta 2,VS 2010。

namespace ParellelJob { class Program { BlockingCollection serviceToSolutionShare; static void Main(string[] args) { Program p = new Program(); p.serviceToSolutionShare = new BlockingCollection(); ServiceStage svc = new ServiceStage(ref p.serviceToSolutionShare); SolutionStage sol = new SolutionStage(ref p.serviceToSolutionShare); var svcTask = Task.Factory.StartNew(() => svc.Execute()); var solTask = Task.Factory.StartNew(() => sol.Execute()); while (!solTask.IsCompleted) { } } } class ServiceStage { BlockingCollection outputCollection; public ServiceStage(ref BlockingCollection output) { outputCollection = output; } public void Execute() { var di = new DirectoryInfo(@"C:\temp\testfiles"); var files = di.GetFiles(); foreach (FileInfo fi in files) { using (var fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.Read)) { int b; var ms = new MemoryStream(); while ((b = fs.ReadByte()) != -1) { ms.WriteByte((byte)b); //OutOfMemoryException Occurs Here } var f = new FileHolder(); f.filename = fi.Name; f.contents = ms; outputCollection.TryAdd(f); } } outputCollection.CompleteAdding(); } } class SolutionStage { BlockingCollection inputCollection; public SolutionStage(ref BlockingCollection input) { inputCollection = input; } public void Execute() { FileHolder current; while (!inputCollection.IsCompleted) { if (inputCollection.TryTake(out current)) { using (var fs = new FileStream(String.Format(@"c:\temp\parellel\{0}", current.filename), FileMode.OpenOrCreate, FileAccess.Write)) { using (MemoryStream ms = (MemoryStream)current.contents) { ms.WriteTo(fs); current.contents.Close(); } } } } } } class FileHolder { public string filename { get; set; } public Stream contents { get; set; } } } 

主逻辑似乎没问题,但是如果在main中的那个空的while循环是文字,那么你正在烧掉不必要的CPU周期。 最好更好地使用solTask​​.Wait()。

但是如果单个文件可以以GB为单位运行,那么你仍然存在至少在内存中保存1个的问题,通常是2个(1个正在读取,1个正在处理/写入。

PS1:我刚刚意识到你没有预先分配MemStream。 这很糟糕,它必须经常为一个大文件重新resize,这会花费大量内存。 更好地使用以下内容:

 var ms = new MemoryStream(fs.Length); 

然后,对于大文件,您必须考虑大对象堆(LOH)。 您确定不能分段处理文件并处理它们吗?

PS2:你不需要构造函数参数的ref,但这不是问题。

只需快速查看,即可获得ServiceStage.Execute方法

 var ms = new MemoryStream(); 

我没有看到你在哪里关闭ms或在使用中。 你确实在其他课程中使用。 这是一回事。