【问题标题】:C# System.OutOfMemoryException when Creating New Array创建新数组时出现 C# System.OutOfMemoryException
【发布时间】:2017-10-13 13:23:10
【问题描述】:

我正在将文件读入一个数组;这是相关代码;为每个文件创建一个新的 DiskReader,并使用 OpenFileDialog 确定路径。

 class DiskReader{
// from variables section:
    long MAX_STREAM_SIZE = 300 * 1024 * 1024; //300 MB


    FileStream fs;
    public Byte[] fileData;

...

// Get file size, check it is within allowed size (MAX)STREAM_SIZE), start process including progress bar.

using (fs = File.OpenRead(path))
            {
                if (fs.Length < MAX_STREAM_SIZE)
                {
                    long NumBytes = (fs.Length < MAX_STREAM_SIZE ? fs.Length : MAX_STREAM_SIZE);
                    updateValues[0] = (NumBytes / 1024 / 1024).ToString("#,###.0");
                    result = LoadData(NumBytes);
                }
                else
                {
                    // Need for something to handle big files
                }

                if (result)
                {
                    mainForm.ShowProgress(true);
                    bw.RunWorkerAsync();
                }

            }

...

    bool LoadData(long NumBytes)
    {
        try
        {
            fileData = new Byte[NumBytes];
            fs.Read(fileData, 0, fileData.Length); 
            return true;
        }
        catch (Exception e)
        {
            return false;
        }
    }

我第一次运行它时,它运行良好。我第二次运行它时,有时它运行良好,大多数时候它会在

处引发 System.OutOfMemoryException

[编辑:

“第一次运行这个”是一个错误的选择,我的意思是当我启动程序并打开一个文件时很好,当我尝试在不退出程序的情况下打开另一个文件时出现问题。当我打开第二个文件时,我将 DiskReader 设置为一个新实例,这意味着 fileData 数组也是一个新实例。我希望这能让它更清楚。]

  fileData = new Byte[NumBytes]; 

它运行并抛出异常没有明显的模式。

我认为这无关紧要,但虽然最大文件大小设置为 300 MB,但我用来测试的文件大小在 49 到 64 MB 之间。

关于这里出了什么问题以及如何纠正它的任何建议?

【问题讨论】:

  • “我第一次运行这个”是什么意思?它是一个单独的程序吗?在您再次调用此代码之前它是否完全关闭并完全重新启动?因为异常清楚地表明你的内存已满。您可能会将旧数组保存在内存中。它看起来与文件流和磁盘无关。
  • 您打开了多少个文件,或者您同时启动了多少个程序实例? System.OutOfMemoryException rly 表示你的内存不足。这部分代码没有问题。发布你留下的内容
  • 如果您在短时间内创建和删除大型数组,它们可能没有足够快地被垃圾收集 - 强制垃圾收集可以解决这个问题。以下是一些给出不同观点的链接:social.msdn.microsoft.com/Forums/vstudio/en-US/…stackoverflow.com/questions/14724107/…stackoverflow.com/questions/4688348/…
  • 如果你这样做会痛,那么不要那样做。将大文件读入数组是一种糟糕的做法。流式传输大文件。
  • 如果您遇到内存问题,请使用内存分析器找出问题的原因,而不是猜测。

标签: c# arrays out-of-memory


【解决方案1】:

如果仅在该行引发异常,那么我的猜测是您的代码中的其他地方有问题,正如 cmets 所建议的那样。阅读该异常here 的文档,我敢打赌,您在某处调用此函数的次数过多,只是超过了内存中对象长度的限制,因为代码中似乎没有任何问题点你发布了。

【讨论】:

    【解决方案2】:

    fs.Length 属性要求评估整个流,因此无论如何都要读取文件。尝试做类似的事情

        byte[] result;
        if (new FileInfo(path).Length < MAX_STREAM_SIZE)
        {
            result = File.ReadAllBytes(path);
        }
    

    另外根据您的需要,您可能会避免使用字节数组并直接从文件流中读取数据。这应该有更少的内存占用

    【讨论】:

    • Jacek,请参阅我对 Eric 的评论,即最终需要将超大文件的部分加载到内存中或从内存中加载出来。
    【解决方案3】:

    如果我很清楚你想要做什么,我有这个建议:最好的选择是在开始时分配一个定义的 MAX 大小的静态数组。然后保留该数组,仅用另一个文件中的新数据填充它。这样你的记忆应该绝对没问题。您只需将文件大小存储在一个单独的变量中,因为数组将始终具有相同的 MAX 大小。

    这是具有自动内存管理的系统中的一种常见方法 - 当您在开始时分配恒定大小的内存然后在计算期间从不分配任何内容时,它会使程序更快,因为垃圾收集器不会运行多次。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-04
      • 2018-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多