C# 为什么我得到一个System.OutOfMemoryException

C# 为什么我得到一个System.OutOfMemoryException,c#,.net,linq,linq-to-sql,out-of-memory,C#,.net,Linq,Linq To Sql,Out Of Memory,我正在使用LINQtoSQL。 代码如下: Dictionary<string, int> allResults; using (var dc= new MyDataContext()) { dc.CommandTimeout = 0; allResults = dc.MyTable.ToDictionary(x => x.Text, x => x.Id); } 我了解到这里的垃圾压缩没有帮助,一旦skip=900000,就会在while循环的第一行抛出

我正在使用LINQtoSQL。 代码如下:

Dictionary<string, int> allResults;
using (var dc= new MyDataContext())
{
    dc.CommandTimeout = 0;
    allResults = dc.MyTable.ToDictionary(x => x.Text, x => x.Id);
}
我了解到这里的垃圾压缩没有帮助,一旦skip=900000,就会在while循环的第一行抛出内存不足异常


问题出在哪里?我该如何解决这个问题?

在不考虑内存容量计算的情况下(因为可能存在编码问题,很容易使数据大小翻倍),我将尝试给出一些提示

从问题的原因开始——我的猜测是三百字典导致了大量的分配。 当您向如上所述的词典中添加项时,词典将无法知道应该预分配多少项。这将导致大量的数据重新分配和处理到新创建的字典中。 在向三百字典添加任何项目之前,请设置字典的大小(使用ctor)

请阅读我发表的这篇文章,这篇文章深入研究了字典的内部结构——我相信它会对这些症状有所帮助。

此外,在尝试填充大量数据时,我建议完全控制该过程。 我的建议是:

  • 在字典中预分配插槽(直接在DB上使用计数查询,并将其传递给字典)
  • 使用DataReader填充这些项,而无需将所有查询结果加载到内存中。 如果你知道一个事实(提前知道这一点非常重要)-考虑使用-只有在有许多重复项的情况下您应该测试一下它是如何工作的
  • 内存配置文件代码-您应该只看到字典的一个分配,字符串作为查询中的项的数量(int是值类型-因此它不是作为对象在堆上分配的,而是位于字典内
无论哪种方式,您都应该检查您是在32位还是64位上运行。NET4.5更喜欢32位。(在任务管理器或项目属性上检查)

希望这有帮助,
Ofir.

您是否有足够的内存同时容纳所有这些内存?旁注:确保您的进程以x64运行-默认情况下,任何CPU都运行x86(“首选32位”)@Joe,请参阅我在上面对sous2817的说明。不过,你们两个可能有点了解。我想我需要更改配置文件:默认情况下,.NET Framework不支持大于2 GB的阵列,但在.NET Framework 4.5中,您可以使用应用程序配置文件中的元素来启用大于此大小的阵列。来源:@Magnus,访问内存中的集合总是比访问任何外部数据源都要快,不管它的索引有多好。我的兴趣是找出这里出了什么问题,以及如何修复它,而不是重新设计产品以避免这个错误。2GB/对象无论如何都不适用于这里,字典是一个大的obje集群cts,每个都远远低于该限制。内存分析器可能会有所帮助。
Dictionary<string, int> allResults;
using (var dc = new MyDataContext())
{
   Dictionary<string, int> threeHundred;
   dc.CommandTimeout = 0;
   var tot = dc.MyTable.Count();
   allResults = new Dictionary<string, int>(tot);
   int skip = 0;
   int takeThis = 300000;
   while (skip < tot)
   {
      threeHundred = dc.MyTable.Skip(skip).Take(takeThis).ToDictionary(x => x.Text, x => x.Id);
      skip = skip + takeThis;
      allResults = allResults.Concat(threeHundred).ToDictionary(x => x.Key, x => x.Value);
      threeHundred = null;
      GC.Collect();
    }
}