繁体   English   中英

C#OutOfMemory处理大数据时出现问题

[英]C# OutOfMemory Issue when dealing with large data

在我们的应用程序中,我们使用Windows Service生成报告。 使用存储过程SQL Server中获取报表数据。 在某些情况下,返回的结果集包含250,000条记录(我们对此无济于事,我们需要一口气获得此数据,因为我们需要对此进行一些计算)。

问题

我们的应用程序正在读取器中获取此数据,并且正在自定义对象的自定义集合中转换此数据集。 由于数据量巨大,因此无法将完整的数据存储在自定义对象中,从而导致内存不足。 当我们在执行记录时看到任务管理器的进程使用情况时,它变得非常高,甚至CPU利用率也很高。

我不确定在这种情况下应该怎么做。

  1. 我们可以增加分配给在CLR下运行的单个进程的内存大小吗?
  2. 还有其他解决方法吗?

任何帮助将非常感激

  1. 为什么我一次需要所有数据:我们需要对完整的结果集进行计算
  2. 我们正在使用ADO.NET并将数据集转换为我们的自定义对象(集合)
  3. 我们的系统是32位
  4. 我们无法分页数据
  5. 无法将计算移至SQL Server

此堆栈跟踪可能有帮助:

引发了类型为'System.OutOfMemoryException'的异常。 服务器堆栈跟踪:位于System.Collections.Generic.Dictionary 2.ValueCollection.System.Collections.Generic.IEnumerable<TValue>.GetEnumerator() at System.Linq.Enumerable.WhereEnumerableIterator 1.MoveNext()位于System.Collections.Generic。清单1.InsertRange(Int32 index, IEnumerable System.Collections.Generic上的1.AddRange(IEnumerable 1.InsertRange(Int32 index, IEnumerable 1集合)清单1.InsertRange(Int32 index, IEnumerable C:\\ Ashish-Stuff \\中MyProject.Common.Data.DataProperty.GetPropertiesForType(Type t)的1.AddRange(IEnumerable 1集合) Projects \\ HCPA \\ Dev Branch \\ Common \\ Benefits.Common \\ Data \\ DataProperty.shared.cs:MyProject.Common.Data.Extensions.GetProperties中的第60行[T](T目标)在C:\\ Ashish-Stuff \\ Projects \\ HCPA \\ Dev Branch \\ Common \\ Benefits.Common \\ Data \\ Extensions.shared.cs:MyProject.Common.Data.Factories.SqlServerDataFactoryContract 1.GetData(String procedureName, IDictionary 2参数,Nullable 1 languageId, Nullable 1 pageNumber,第30行可为1页大小)

谢谢,Ashish

您能否每1000行数据将自定义的对象集合序列化到磁盘上的某个位置? 然后,当您返回数据时,是否从这些文件中分页?

有关您的用例的更多信息,为什么需要回退250万行数据将很有帮助。

我的第一个想法是,可以通过某些存储过程在Sql-Server端进行计算。 我怀疑这个方法需要一定的SQL服务器的绝地......但无论如何,你有没有考虑过这样的做法?

我希望看到一个代码示例,突出显示您从何处得到此错误。 是在数据提取本身上(填充读取器)还是在创建对象并将其添加到自定义集合中(填充集合)。

以前我曾遇到过类似的问题,涉及非常大的数据集,但在将其尽可能长时间地保留在流中方面取得了巨大的成功。 流将数据直接保存在内存中,直到您完成对象的构建,您才真正拥有对整个混乱的直接访问权限。 现在,由于堆栈跟踪显示“ MoveNext”操作上的错误,因此这可能对您不起作用。 然后我会说尝试对数据进行分块,一次抓取1万行或类似的东西,我知道这可以使用SQL来完成。 但是,这将使数据读取花费更长的时间。

编辑

如果您从数据库中将其读取到本地流中,然后又将其传递(只是注意不要将其关闭),那么就不应遇到这些问题。 制作一个数据包装器类,您可以使用开放流和开放阅读器来传递它。 将数据存储在流中,然后使用包装函数从中读取所需的特定数据。 诸如GetSumOfXField()AverageOfYValues()等之类的东西……数据永远不会存在于活动对象中,但是您不必为此一直返回数据库。

伪示例

    public void ReadingTheDataFunction()
    {
        DBDataReader reader = dbCommand.ExecuteReader();
        MyDataStore.FillDataSource(reader)
    }

    private void FillDataSource(DbDataReader reader)
    {
        StreamWriter writer = new StreamWriter(GlobaldataStream);
        while (reader.Read())
            writer.WriteLine(BuildStringFromDataRow(reader));
        reader.close();
    }

    private CustomObject GetNextRow()
    {
        String line = GlobalDataReader.ReadLine();
        //Parse String to Custom Object
        return ret;
    }

从那里绕过MyDataStore,只要不关闭流和阅读器,就可以移动位置,查找单个条目,编译求和和平均值等。您甚至不必真正知道自己在哪里。只要您仅通过接口函数与活动对象交互,就不会处理该对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM