数据表内存消耗过大

5
我正在将CSV数据从文件加载到datatable中进行处理。
问题是,我想处理多个文件,并且我的datatable测试显示出巨大的内存消耗。我尝试了一个37MB的CSV文件,内存增长到了240MB,这明显太多了。我阅读到datatable中存在一些额外开销,并且可以接受约70MB的大小,但不应该是240MB,这意味着它比原始大小大了六倍。我在这里阅读到datatable需要比POCO更多的内存,但差距太大了。
我运行了内存分析器并查看了内存泄漏以及内存位置。我发现datatable列之间有6MB到19MB的字符串填充,datatable有约20列。这些值存储在列中吗?为什么会占用这么多内存?我该如何减少内存消耗。以这种内存消耗方式,datatables似乎无法使用。
还有其他人遇到过datatable的这些问题吗?或者是我在做错什么吗?
PS:我尝试了一个70MB的文件,datatable增长到了500MB!
以下是一个小的测试案例: 这个37MB的CSV文件(21列)使内存增加到了179MB。
    private static DataTable ReadCsv()
    {
        DataTable table = new DataTable();
        table.BeginLoadData();

        using (var reader = new StreamReader(File.OpenRead(@"C:\Develop\Tests\csv-Data\testdaten\test.csv")))
        {               
            int y = 0;
            int columnsCount = 0;
            while (!reader.EndOfStream)
            {
                var line = reader.ReadLine();
                var values = line.Split(',');

                if (y == 0)
                {
                    columnsCount = values.Count();
                    // create columns
                    for (int x = 0; x < columnsCount; x++)
                    {
                        table.Columns.Add(new DataColumn(values[x], typeof(string)));
                    }
                }
                else
                {
                    if (values.Length == columnsCount)
                    {
                        // add the data
                        table.Rows.Add(values);
                    }
                }

                y++;
            }

            table.EndLoadData();
            table.AcceptChanges();

        }

        return table;
    }

你想让我们猜测还是给我们展示一些代码让我们看看? - Ehsan
我猜你的代码里肯定还有其他对象吧? - King King
1
内存很便宜,但是:也许这可以帮助您找到更节省内存的解决方案:https://dev59.com/-nVC5IYBdhLWcg3wfxM8 - dcaswell
1
@user814064 “内存很便宜”?真的吗?今天我们使用的计算机都拥有“8GB内存或更多”,这是事实,但仍然有许多人在使用“2GB内存或更少”的计算机。我认为,如果实际数据只有“2x MB”,那么一个消耗“2xx MB内存”的应用程序并不是一个微不足道的问题。 - King King
1
是的,真的。这里没有人开始遇到任何成本问题。我可以在我的电脑上使用256兆字节的内存几秒钟(或几分钟),而不会看到巨大的成本。我还提供了一个链接到有用的帖子,解释了为什么datatables具有很大的内存占用。 - dcaswell
2个回答

6
DataSet 和它的子类 DataTableDataRow 等构成了一个内存关系型数据库。尽管这样做(某些情况下)非常方便,但涉及到很多开销。
如果内存是一个问题,
- 使用有类型属性的领域对象表示 CSV 文件中的每一行。 - 创建一个自定义集合(或仅使用 IList<T> 来保存它们)。 - 或者,构建一个轻量级类来具有 DataTable 的基本语义: - 按编号选择一行 - 按行号和列名或数字选择行中的列。 - 知道有序的列名称集合 - 奖励: 按名称或序数号选择列,并按每行一个值的方式接收其值列表。
您确定需要内存表示您的 CSV 文件吗?您能否像 Sebastien Lorion 的 Fast CSV Reader 那样通过 IDataReader 访问它们?

是的,但是6-7的因素不可能存在。否则我的代码肯定有问题,数据表也就没法用了。这就是为什么我要求其他用户提供统计/经验值来进行比较。没有数据库会有这样的开销。如果我把它们放在Sqlite中,它就不会变得那么大。我编写了自己的csv读取器、AdoAdapter、XmlReader,并设计了应用程序以便在内存中使用datables,并且如果乘以2的因素,它可以工作。但是这种开销会破坏我的设计。其他用户有什么经验? - JohnnyBravo75

0

DataTables是将表格数据放入内存并添加许多与表格相关的功能的通用解决方案。如果开销对您来说不可接受,您有以下选项:1)编写自己的DataTable类,以消除您不需要的开销;2)使用其他表示形式仍然可以实现您所需的功能,例如基于POCO或XMLDocument(可能具有同样多甚至更多的开销,但从未真正担心过)。3)停止尝试将所有内容加载到内存中,只需根据需要从外部存储中获取数据即可。


已尝试使用 Telerik 的 Silverlight 数据表格(http://blogs.telerik.com/vladimirenchev/posts/09-04-23/lightweight-datatable-for-your-silverlight-applications.aspx),但其并不轻量级,会消耗更多内存。问题在于,如果需要编辑功能,则无法轻量级化。否则,使用字典列表更加轻量级,这是我的唯一希望。 - JohnnyBravo75
  1. 基于POCO并不是一个替代方案,因为我没有特殊的数据。每个数据都有另一种结构。
  2. 是的,这就是我正在评估的。问题是,我需要处理数据,建立关键列/索引,对它们进行排序...也许像sqlite这样的轻量级数据库是可行的选择。
- JohnnyBravo75
这听起来很像我的第三个选项——有几个数据库选项。轻量级可能是一个不错的选择,或者你可能需要更可扩展的东西,但是当你的信息不能方便地放入内存中或者当你需要一个持久性存储时,数据库基本上是你应该考虑使用的第一件事情。这就是它们所做的。如果你现在进行更改,好处是随着你继续添加数据,你不会突然“撞墙”。 - Gary Walker
只是一个想法。你有在你的DataTable上调用BeginLoadData()吗?我从未亲自比较过开销,我猜想你已经尝试过了。别忘了EndLoadData()。 - Gary Walker
是的,我尝试了BeginLoadData()和EndLoadData(),但它们没有产生任何区别。我展示了一段示例代码... - JohnnyBravo75
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接