C# 为什么处理实体上下文不能释放内存

C# 为什么处理实体上下文不能释放内存,c#,asp.net,entity-framework,memory,glimpse,C#,Asp.net,Entity Framework,Memory,Glimpse,在我的测试中,我逐行读取一个文本文件,并插入一个实体以及其他相关实体。问题是当插入太多时,我会收到内存不足异常 为了防止这种情况,我为每50行创建一个新的DbContext,并处理旧的DbContext。据我所知,这将从早期的实体操作中释放内存,但内存会继续增加,如果文件足够大,则会发生内存不足异常。这与实体代码有关,就像我删除了添加实体的代码行一样,内存保持一致的使用 下面是我的代码的简化版本 public class TestClass { public void ImportData

在我的测试中,我逐行读取一个文本文件,并插入一个实体以及其他相关实体。问题是当插入太多时,我会收到内存不足异常

为了防止这种情况,我为每50行创建一个新的DbContext,并处理旧的DbContext。据我所知,这将从早期的实体操作中释放内存,但内存会继续增加,如果文件足够大,则会发生内存不足异常。这与实体代码有关,就像我删除了添加实体的代码行一样,内存保持一致的使用

下面是我的代码的简化版本

public class TestClass
{

  public void ImportData(byte[] fileBytes)
  {
    using (Stream stream = new MemoryStream(fileBytes))
    {
        TextFieldParser parser = new TextFieldParser(stream);
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");

       while (!parser.EndOfData)
       {
          //Processes 50 lines creates a new DbContext each time its called
          ImportBatch(parser);          
       } 
    }
  }

  public void ImportBatch(TextFieldParser parser)
  {
    using(myDbContext context = new myDbContext())
    {
      context.Configuration.AutoDetectChangesEnabled = false;

      int batchCount = 0;
      while (!parser.EndOfData && batchCount < 50)
      {
         string[] fields = parser.ReadFields();

         //Here I call some code that will add an entity and add releated entities
         //In its navigation properties
         MyService.AddMyEntity(fields,myDbContext);

         batchCount++;
      } 

     myDbContext.ChangeTracker.DetectChanges();
     myDbContext.SaveChanges();

    }
  }
}
另一次编辑

经过更多的测试后发现,这与Spiew profiler有关。我在我的项目中加入了一瞥,web配置有一个类似于下面的部分

  <glimpse defaultRuntimePolicy="On" endpointBaseUri="~/Glimpse.axd">
<tabs>
  <ignoredTypes>
    <add type="Glimpse.Mvc.Tab.ModelBinding, Glimpse.Mvc5"/>
    <add type="Glimpse.Mvc.Tab.Metadata, Glimpse.Mvc5"/>

  </ignoredTypes>
</tabs>
<inspectors>
  <ignoredTypes>
    <add type="Glimpse.Mvc.Inspector.ModelBinderInspector, Glimpse.Mvc5"/>
  </ignoredTypes>
</inspectors>


将defaultRuntimePolicy关闭可修复内存泄漏。仍然不知道为什么会这样,因为无论何时调用ImportBatch(解析器),它都会创建一个新的DbContext。不是每50个都有1个DbContext。您可以尝试使用get属性计数并将上下文返回给您。大概是这样的:

int _batchCount = 0;
public myDbContext _db;
public myDbContext Db
{
    get
    {
        // If batchCount > 50 or _db is not created we need to create _db
        if (_db == null || _batchCount > 50)
        {
            // If db is  already created _batchcount > 50
            if (_db != null)
            {
                _db.ChangeTracker.DetectChanges();
                _db.SaveChanges();
                _db.Dispose();
            }

            _db = new myDbContext();
            _db.Configuration.AutoDetectChangesEnabled = false;
            _batchCount = 0;
        }
        batchCount++;
        return _db;
    }
}

另外在
MyService.AddMyEntity(字段)中
您使用的是
MyService
类中的DbContext,而不是在using line中创建的DbContext。

对对象调用
Dispose
,不一定会释放内存。当对象不再被任何活动对象引用时,垃圾收集器会将其从内存中删除。调用
Dispose
可能会释放其他资源(例如,在
DbContext
的情况下关闭打开的SQL连接),但只有当对象不再被引用时,它才会成为垃圾收集的候选对象

无法保证垃圾收集器将在特定时间点运行。调用
Dispose
肯定不会导致它运行。话虽如此,我很惊讶它在内存耗尽之前不会运行。您可以强制它与
GC.Collect一起运行,但这确实不是必需的


有可能您仍然有一个对上下文对象的引用,导致它们被认为不符合垃圾收集的条件。例如,您将
myDbContext
传递给您的服务层中的
AddEntity
方法-该方法是否存储了包含对上下文的反向引用(甚至是间接引用)的内容?

您不是一直在添加前50个字段吗?@GregoryHouseMD您的权利,我的错误,将进行编辑。无论哪种方式,这都只是演示我的问题的简化代码,因为您正在处理一个对象并不意味着它正在被垃圾收集。您正在运行Visual Studio 2015吗?如果没有,请获取Community edition并在分析器运行时进行调试。您将看到垃圾收集活动。如果没有看到任何垃圾收集,则可能必须在ImportBatch方法末尾执行一些手动垃圾收集。可能
MyService.AddMyEntity
会泄漏内存。你也可以发布这个方法的代码吗?为什么只在上下文后面创建另一个上下文而不处理上下文呢?这并不比原来的循环好——您刚刚将引用移动到一个类字段。实际上,dispose of context会创建另一个循环,因为它需要这样做。如果_batchCount>50,则每当调用较新的一个时,它都会创建另一个,并处理旧的。我想这就是我们在那里要做的。
int _batchCount = 0;
public myDbContext _db;
public myDbContext Db
{
    get
    {
        // If batchCount > 50 or _db is not created we need to create _db
        if (_db == null || _batchCount > 50)
        {
            // If db is  already created _batchcount > 50
            if (_db != null)
            {
                _db.ChangeTracker.DetectChanges();
                _db.SaveChanges();
                _db.Dispose();
            }

            _db = new myDbContext();
            _db.Configuration.AutoDetectChangesEnabled = false;
            _batchCount = 0;
        }
        batchCount++;
        return _db;
    }
}