我正在使用Linq to Sql。 这是代码:
Dictionary<string, int> allResults;
using (var dc= new MyDataContext())
{
dc.CommandTimeout = 0;
allResults = dc.MyTable.ToDictionary(x => x.Text, x => x.Id);
}
它在64位机器上运行,编译是AnyCPU。它抛出一个System.OutOfMemoryException。
这将访问SQL Server数据库。 Id字段映射到SQL Server int字段,Text字段映射到Text(nvarchar(max))字段。运行select COUNT(*) from TableName
会产生1,173,623条记录,而运行select sum(len(Text)) from TableName
会产生48,915,031条记录。由于int是32位整数,因此id应该只占用4.69MB空间而字符串小于1GB。所以我们甚至没有碰到2GB /对象限制。
然后我以这种方式更改代码:
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();
}
}
我知道这里的垃圾收集没有帮助,并且一旦跳过= 900,000,就会在while循环的第一行抛出内存不足异常。
有什么问题,如何解决这个问题?
答案 0 :(得分:1)
没有计算内存中应该花多少钱(因为可能存在编码问题,可能会轻易地使数据大小翻倍),我将尝试给出一些指示。
从问题的原因开始 - 我的猜测是threeHundred字典导致了大量的分配。 当您将项目添加到上面的字典时,字典将无法知道应预先分配的项目数。这将导致大量重新分配并将所有数据复制到新创建的词典中。 请在添加任何项目之前将大小(使用ctor)设置为threeHundred字典。
请阅读我发表的文章,深入研究词典内幕 - 我相信它会对这些症状有所了解。 http://www.codeproject.com/Articles/500644/Understanding-Generic-Dictionary-in-depth
此外,在尝试填充大量数据时,我建议完全控制该过程。 我的建议是:
无论哪种方式,您都应该检查您是在32位还是64位上运行。 .Net 4.5更喜欢32位。 (在任务管理器或项目属性上查看)
希望这有帮助, 奥菲尔。