c# - 内存不足异常 : using DbContext in Task

标签 c# out-of-memory dbcontext

这是我目前正在处理的以下设置:

  • 我有一个 sql 表,其中包含 ~1.000.000 个条目,我需要更新
  • 更新发生在一个单独的线程中(由任务启动)
  • 由于线程中的内存有限,我以每批 1000 个条目的批处理处理列表 (在主线程的测试项目中运行/没有任何任务时,没有 OOM 异常)
  • UpdateList() 函数更新列表的字段或为该表或 DbContext 中的其他表创建新记录
  • Process_Failure() 函数中,我有一个用于整个列表的上下文实例
  • Process_Success() 函数中,我将 while 循环移到了上下文之外

private void Process_Success()
{
    var totalProcessedCounter = 0;

    while( true )
    {
        using( var context = new MyDbContext() )
        {
            var list = context.MyClass.OrderBy( x => x.Id )
                .Skip( totalProcessedCounter ).Take( 1000 )
                .ToList();

            if( !list.Any() )
                break;

            UpdateList( list );

            totalProcessedCounter += list.Count;
        }
    }
}

private void Process_Failure()
{
    var totalProcessedCounter = 0;

    using( var context = new MyDbContext() )
    {
        while( true )
        {
            var list = context.MyClass.OrderBy( x => x.Id )
                .Skip( totalProcessedCounter ).Take( 1000 )
                .ToList(); // throws OutOfMemoryException

            if( !list.Any() )
                break;

            UpdateList( list );

            totalProcessedCounter += list.Count;
        }
    }
}

private void UpdateList( List<MyClass> list )
{
    var doSaveChanges = false;

    list = list.Where( x => SomeFilter( x ) ).ToList();

    using( var context = new MyDbContext() )
    {
        foreach( var item in list )
        {
            ChangeItem( item );
        }

        if( doSaveChanges )
            context.SaveChanges();
    }
}

当我在 UpdateList() 的嵌套函数调用中创建另一个实例时,以某种方式污染/填充了 context

最佳答案

之所以得到异常是因为DbContext缓存了the data you read from DB ,因此在某些时候,如果您不断向其缓存中添加实体,您将炸毁内存,并且您将获得 OutOfMemoryException。实体不会被 GC 清除,因为它们正被 DbContext 引用。

尝试使用 .AsNoTracking():

private void Process_NoTracking()
{
    var totalProcessedCounter = 0;

    using( var context = new MyDbContext() )
    {
        while( true )
        {
            var list = context
                          .MyClass
                          .AsNoTracking()
                          .OrderBy( x => x.Id )
                          .Skip( totalProcessedCounter )
                          .Take( 1000 )
                          .ToList(); 

            if( !list.Any() )
                break;

            UpdateList( list );

            totalProcessedCounter += list.Count;
        }
    }
}

但如果您不跟踪实体,更新它们 is more difficult (阅读“将现有实体附加到上下文”),因为这些实体不属于任何上下文并且不会被跟踪。

我不会将 EF 用于这样的事情,这对于 UPDATE/SELECT SQL 语句来说似乎是一个很好的任务。

关于c# - 内存不足异常 : using DbContext in Task,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39464913/

相关文章:

c# - FTDI 芯片 C# 编程 - 如何读取所有缓冲区?

c# - 仅根据用户名存储和检索大量头像?

c# - 抽象类调用通用方法与此 - 不会编译

python - 摆脱 maxpooling 层会导致运行 cuda 内存错误 pytorch

c# - 如何在方法期间通过依赖注入(inject)从池中获取 DbContext 实例?

entity-framework - Entity Framework - 我应该从 BLL 还是 DAL 调用 DbContext

c# - 为什么调度程序 BeginInvoke 在 C# Windows 窗体应用程序中 Control BeginInvoke 成功的地方失败?

c# - 生成排列时出现 System.OutOfMemoryException

java - Tomcat 8.5 Wildfly 15 Java 8 OutOfMemoryError 和启动速度非常慢

c# - 将 DbContext SaveChanges 与事务一起使用