1

我知道以前有人问过这个问题,但我似乎无法用我读过的答案来解决这个问题。我有一个 CSV 文件 ~ 1.2GB,如果我像 32 位一样运行进程,我会得到 outOfMemoryException,如果我将它作为 64 位进程运行它就可以工作,但它仍然需要 3.4GB 的内存,我知道我在我的 customData 类中存储了很多数据,但仍然有 3,4gb 的内存?,我在读取文件时做错了什么吗?dict 是一本字典,其中我只有一个映射到要保存某些内容的属性,具体取决于它所在的列。我是否以正确的方式阅读?

StreamReader reader = new StreamReader(File.OpenRead(path));
while(!reader.EndOfStream)  {
            String line = reader.ReadLine();
            String[] values = line.Split(';');
            CustomData data = new CustomData();
            string value;
            for (int i = 0; i < values.Length; i++) {
                dict.TryGetValue(i, out value);
                Type targetType = data.GetType();
                PropertyInfo prop = targetType.GetProperty(value);
                if(values[i]==null)
                {
                    prop.SetValue(data, "NULL",null);
                }
                else
                {
                    prop.SetValue(data, values[i], null);
                }

            }
            dataList.Add(data);
        }
4

2 回答 2

3

您使用流阅读器似乎没有任何问题,您在内存中读取了一行,然后忘记了它。

但是,在 C# 中,字符串在内存中编码为 UTF-16,因此平均一个字符在内存中消耗 2 个字节。

如果您的 CSV 还包含许多要转换为的空字段,则"NULL"每个空字段最多可添加 7 个字节。

因此,总的来说,由于您基本上将文件中的所有数据都存储在内存中,因此您需要几乎 3 倍于内存中的文件大小也就不足为奇了。

实际的解决方案是通过 N 行来解析数据,处理它们,然后从内存中释放它们。

注意:考虑使用 CSV 解析器,CSV 不仅仅是逗号或分号,如果您的某个字段包含分号、换行符、引号... 怎么办?

编辑

实际上每个字符串在内存中最多占用 20+(N/2)*4 个字节,请参阅C# in Depth

于 2012-07-13T08:04:24.470 回答
3

好的,这里有几点。

  • 正如评论中指出的那样,x86 下的 .NET 每个进程只能消耗 1.5GBytes,因此请考虑您的最大内存为 32 位

  • StreamReader 本身会有开销。我不知道它是否将整个文件缓存在内存中(也许有人可以澄清一下?)。如果是这样,分块读取和处理文件可能是更好的解决方案

  • CustomData 类,它有多少个字段,创建了多少个实例?请注意,x86 中的每个引用都需要 32 位,x64 中的每个引用需要 64 位。因此,如果您有 CustomData 类,它有 10 个 System.Object 类型的字段,则每个 CustomData 类在存储任何数据之前都需要 88 个字节。

  • dataList.Add 在最后。我假设您要添加到通用列表?如果是这样,请注意 List 使用加倍算法来调整大小。如果列表中有 1GByte 并且它需要多 1 个字节的大小,它将创建一个 2GByte 数组并在调整大小时将 1GByte 复制到 2GByte 数组。所以突然之间 1GByte + 1 字节实际上需要 3GBytes 来操作。另一种选择是使用预先确定大小的数组

于 2012-07-13T08:10:14.430 回答