簡體   English   中英

關於MemoryStream編寫的OutOfMemoryException

[英]OutOfMemoryException on MemoryStream writing

我有一個小樣本應用程序我正在努力嘗試獲得一些新的.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<FileHolder> serviceToSolutionShare;
    static void Main(string[] args)
    {
        Program p = new Program();
        p.serviceToSolutionShare = new BlockingCollection<FileHolder>();
        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<FileHolder> outputCollection;
    public ServiceStage(ref BlockingCollection<FileHolder> 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<FileHolder> inputCollection;
    public SolutionStage(ref BlockingCollection<FileHolder> 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中的空循環是文字,那么你正在燒掉不必要的CPU周期。 最好更好地使用solTask​​.Wait()。

但是,如果單個文件可以以GB為單位運行,那么仍然存在至少在內存中保留1個的問題,通常為2(1個正在讀取,1個正在處理/寫入。

PS1:我剛剛意識到你沒有預先分配MemStream。 這很糟糕,它必須經常為一個大文件重新調整大小,這會花費大量內存。 更好地使用以下內容:

var ms = new MemoryStream(fs.Length);

然后,對於大文件,您必須考慮大對象堆(LOH)。 您確定無法分段處理文件並處理它們嗎?

PS2:你不需要構造函數參數的ref,但這不是問題。

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

var ms = new MemoryStream();

我沒有看到你在哪里關閉ms或在使用中。 你確實在其他課程中使用。 這是一回事。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM