<分区>
我正在使用一些代码来比较大量对象并存储所有匹配项。
不出所料,我刚刚遇到了一个System.OutofMemoryException
我该如何解决这个问题?
在比较过程中,我应该写入内存,然后让其他东西将结果写入磁盘/rdbms。即创建一个缓冲区。
<分区>
我正在使用一些代码来比较大量对象并存储所有匹配项。
不出所料,我刚刚遇到了一个System.OutofMemoryException
我该如何解决这个问题?
在比较过程中,我应该写入内存,然后让其他东西将结果写入磁盘/rdbms。即创建一个缓冲区。
最佳答案
事实上,它确实取决于您的环境,尤其是取决于您的操作系统 x86 或 x64。在此处查看更多详细信息:Memory in depth
1.您拥有高级方案,其中流媒体是您所需要的。确切的解决方案取决于您从何处提取数据。在从 SQL 数据库中提取数据的情况下,您可以对 SqlDataReader 使用流式处理,在这种情况下它与异步紧密耦合,示例代码:
using (SqlDataReader reader = await command.ExecuteReaderAsync(CommandBehavior.SequentialAccess))
{
if (await reader.ReadAsync())
{
if (!(await reader.IsDBNullAsync(0)))
{
using (var dataStream = reader.GetStream(0))
{
//process the data
}
}
}
}
此链接将显示更多详细信息:Retrieving large data set .但是,请记住,这种方法会强制您在连接字符串中使用异步以及处理异步代码,这总是会增加复杂性,尤其是当您想要用规范/测试覆盖它时。
2.另一种方法是批处理,即将数据缓冲到某个可接受的限制,然后公开批处理以供使用代码,之后继续获取新的批处理数据,除非所有内容都已加载,示例代码:
while(true)
{
int count = 0;
bool canRead = reader.Read();
while(canRead)
{
canRead = reader.Read();
count++;
if (count >= batchSize)
break;
}
if (!canRead)
break;
}
您可以通过估计 1 行数据的大小(基于表架构,msdn article)来粗略计算批处理的大小,或者只是使其可配置并使用最合适的值。这种方法的主要优点是您需要对代码进行最少的更改,并且代码本身保持同步。缺点是您必须保持事件连接或每次都打开一个新连接,而是维护您已经读取的记录和仍然需要获取的记录。
最后,这两个选项都会迫使你考虑一些更高级的问题,比如如果只获取了一部分数据,然后连接丢失你应该怎么做(需要一些故障转移机制),取消的能力一定超时后长时间运行的检索操作等。
总而言之,如果您不想处理大数据带来的额外复杂性,请将此任务委派给市场上可用的任何东西,即数据库或第 3 方框架。如果你觉得你的团队有足够的技能来做这件事,那就继续自己实现吧——将比较结果保存在磁盘文件中,利用内存缓存或者只是将该数据推送到数据库中
关于c# - 处理大型数据集和内存限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24293105/