【问题标题】:Out Of Memory Exception when using less than 1.2 GB?使用小于 1.2 GB 时出现内存不足异常?
【发布时间】:2016-11-17 18:00:46
【问题描述】:

我在这里遇到了一个棘手的情况。在通过 HDFDotNet API 将大型 CSV 数据集写入 H5 文件时,我试图避免出现内存不足的异常。但是,当尝试对与第一次迭代大小相同的文件数据进行第二次循环时,我得到了内存不足异常,即使第一个有效而第二个无效,并且使用的内存量应该是远低于~1.2GB 的上限。由于 API 的限制,我已经确定了一次要读取的块的大小以及一次需要写入的块的大小。 CSV 文件长约 105k 行,宽约 500 列。

private void WriteDataToH5(H5Writer h5WriterUtil)
{
    int startRow = 0;
    int skipHeaders = csv.HasColumnHeaders ? 1 : 0;
    int readIntervals = (-8 * csv.NumColumns) + 55000;
    int numTaken = readIntervals;

    while (numTaken == readIntervals)
    {
        int timeStampCol = HasTimestamps ? 1 : 0;

        var readLines = File.ReadLines(this.Filepath)
            .Skip(startRow + skipHeaders).Take(readIntervals)
            .Select(s => s.Split(new char[] { ',').Skip(timeStampCol)
            .Select(x => Convert.ToSingle(x)).ToList()).ToList();

        //175k is  max number of cells that can be written at one time
        //(unconfirmed via API, tested and seems to be definitely less than 200k and 175k works)

        int writeIntervals = Convert.ToInt32(175000/csv.NumColumns);

        for (int i = 0; i < readIntervals; i += writeIntervals)
        {
            long[] startAt = new long[] { startRow, 0 };
            h5WriterUtil.WriteTwoDSingleChunk(readLines.Skip(i).Take(writeIntervals).ToList()
                , DatasetsByNamePair[Tuple.Create(groupName, dataset)], startAt);

            startRow += writeIntervals;
        }

        numTaken = readLines.Count;
        GC.Collect();
    }
}

我最终在第二次通过 readlines 部分时遇到内存不足异常

var readLines = File.ReadLines(this.Filepath)
            .Skip(rowStartAt).Take(numToTake)
            .Select(s => s.Split(new char[] { ',' }).Skip(timeStampCol)
            .Select(x => Convert.ToSingle(x)).ToList()).ToList();

在这种情况下,我的读取间隔 var 会达到 50992,而 writeIntervals 会达到大约 350。谢谢!

【问题讨论】:

  • 尽可能避免解析任务。见stackoverflow.com/questions/9642055/…你会遇到转义数据、多行数据等问题。使用别人的工作
  • 我最终找出了问题所在,这与我通过 API 写入 H5 文件的方式有关。我之前已将其上的块大小设置为 {1,1} 默认值,并且尝试写入更大的块会导致它崩溃。此外,将压缩级别设置为 6-8 也有很大帮助。

标签: c# .net csv hdf5


【解决方案1】:

你做了很多不必要的分配:

var readLines = File.ReadLines(this.Filepath)
            .Skip(rowStartAt).Take(numToTake)
            .Select(s => s.Split(new char[] { ',' }) //why you need to split here ?
             .Skip(timeStampCol)
            .Select(x => Convert.ToSingle(x)).ToList()).ToList(); //why 2 time ToList() ?

File.ReadLines 返回Enumerator,因此只需对其进行迭代,在分割每一行后,跳过所需的列,并恢复您需要保存的值。

如果仍然使用少于 1.2GB 的内存,内存异常会怎样,请考虑以下几点:

  1. 您可以尝试为 x64 编译(仍然先重新构建您的代码!)
  2. 无论您做什么,单个集合大小仍然存在限制,即(真)2GB。
  3. 您分配的内存可能比堆栈所能提供的更多,其中 1 MB 用于 32 位进程,4 MB 用于 64 位进程。 Why is stack size in C# exactly 1 MB?

【讨论】:

  • 我需要将逗号中的每个值拆分为二维结构中的“单元格”,以写入 H5 文件,该文件存储数据集并接收结构以写入 2D。
  • 你不能在写入 hdf5 之前拆分吗?
  • 是的,但这会带来什么好处吗?它仍然必须在某个时间点完成
  • 它只适用于一行,当前行并保存。非同时用于文件中的所有行
猜你喜欢
  • 2013-10-05
  • 1970-01-01
  • 2011-12-08
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 2015-07-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多