我有一个数据集大于20m记录的DbContext,它必须转换成不同的数据格式。因此,我将数据读入内存,执行一些任务,然后释放DbContext。代码运行良好,但过一段时间我就会得到OutOfMemoryExceptions。我已经能够将其缩小到下面的代码段,在该代码中,我检索了200万条记录,然后释放它们并再次获取它们。第一次检索工作很好,第二次则抛出异常。
// first call runs fine
using (var dbContext = new CustomDbContext())
{
var list = dbContext.Items.Take(2000000).ToArray();
foreach (var item in list)
{
// perform conversion tasks...
item.Converted = true;
}
}
// second call throws exception
using (var dbContext = new CustomDbContext())
{
var list = dbContext.Items.Take(2000000).ToArray();
foreach (var item in list)
{
// perform conversion tasks...
item.Converted = true;
}
}GC不应该自动释放在第一个使用块中分配的所有内存,这样第二个块就应该像第一个块一样好地运行吗?
在我的实际代码中,我不是一次检索200万条记录,而是在每次迭代中检索0到30K之间的记录。然而,在大约15分钟后,我耗尽了内存,尽管所有的对象都应该已经释放了。
发布于 2015-08-24 20:17:03
重构之后,内存就会被释放。我不知道为什么,但很管用。
private static void Debug()
{
var iteration = 0;
while(true)
{
Console.WriteLine("Iteration {0}", iteration++);
Convert();
}
}
private static void Convert()
{
using (var dbContext = new CustomDbContext(args[0]))
{
var list = dbContext.Items.Take(2000000).ToList();
foreach (var item in list)
{
item.Converted = true;
}
}
}当我在Debug()中将转换()的内容移动到while循环时,就会抛出OutOfMemoryExceptions。
private static void Debug()
{
var iteration = 0;
while(true)
{
Console.WriteLine("Iteration {0}", iteration++);
using (var dbContext = new CustomDbContext(args[0]))
{
// OutOfMemoryException in second iteration
var list = dbContext.Items.Take(2000000).ToList();
foreach (var item in list)
{
item.Converted = true;
}
}
}
}发布于 2015-08-23 03:01:01
我猜你见过陆。可能你的对象比三重空间大,而且它们正在到达那里,因此GC在默认情况下是没有帮助的。
试试这个:https://www.simple-talk.com/dotnet/.net-framework/large-object-heap-compaction-should-you-use-it/
看看你的例外会不会消失。
即在第一部分和第二部分之间添加以下内容:
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect(); 发布于 2015-08-23 07:09:00
IEnumerable有GetEnumerator(),所以您可以尝试这样做,以避免.ToArray()或.ToList() --如果您只想阅读:
// first call
using (var dbContext = new CustomDbContext())
{
foreach (var item in dbContext.Items.Take(2000000))
{
// perform conversion tasks...
item.Converted = true;
}
}
// second call
using (var dbContext = new CustomDbContext())
{
foreach (var item in dbContext.Items.Take(2000000))
{
// perform conversion tasks...
item.Converted = true;
}
}https://stackoverflow.com/questions/32162321
复制相似问题