使用Entity Framework时内存泄漏

时间:2015-05-13 08:27:44

标签: c# entity-framework

我使用EF有一个非常简单的应用程序。但是当它运行一周时,内存使用率很差(一开始只有80MB,一周后只有700MB)。 当我使用dotMemory来配置我的应用程序时。我发现Heap第2代的记忆一直在增加。

only run 40 minutes

我得到一个快照,最后发现ef dbcontext的保留字节是最多的。

enter image description here

我很困惑。我的申请很简单。代码示例:

protected CarbonBrushMonitorEntities _entities = new MYEntities();
public void Add(HistoryData data)
{
   _entities.HistoryDatas.Add(data);
   _entities.SaveChanges();
}  

_entities仅在开始时间首字母一次,然后一直使用。

经常调用函数Add,大约3次/秒

我谷歌很长一段时间,并尝试一些方法,如:

_entities.Configuration.ValidateOnSaveEnabled = false;
_entities.Configuration.AutoDetectChangesEnabled = false;
_entities.Configuration.LazyLoadingEnabled = false;

但这些不起作用。

3 个答案:

答案 0 :(得分:19)

如果你使用实体框架,你应该在你需要它之​​前创建上下文并且尽快处理它

.vcproj

永远不要将内容保留在内存中或在不同的呼叫中共享它。

我通常做的是使用IoC容器注册上下文:

 using (var someContext = new SomeContext())
 {
    // your commands/queries
 }

并使用上下文解析器(当然也在IoC中注册),如:

 DependencyFactory.RegisterType(typeof(SomeContext));

分辨率如下:

 using (var someContext = _contextResolver.ResolveContext())
 {
     // your commands/queries
 }    

EF环境实际上是您的工作单位,一旦您不再需要它就应该处理掉。

答案 1 :(得分:2)

另一种方法是清除各个关注实体或什至是各个实体的changetracker 所有实体中。这是通过将实体状态更改为“已分离”来完成的。这是在dbContext.SaveChangesAsync()

之后调用的
protected void DisposeDbset<T>() where T : class
        {
            var Tname = typeof(T).Name;
            var changetrackercollection = _unitOfWork.dbContext.ChangeTracker.Entries<T>();
            foreach (var item in changetrackercollection.ToList())
            {
                item.State = EntityState.Detached;
            }
            GC.Collect();
        }

我最近遇到了类似的情况,我在批处理操作中插入了300万行。插入行后,所有行的更改跟踪信息都保留在内存中,并且实体状态为未更改。因此,在每次SaveChangesAsync()调用之后,changetracker都会累积。

我无法为每个批次解析新的实例dbcontext,因为这是一个更昂贵的操作。

仅供参考,我已经配置了dbConetext.ChangeTracker.QueryTrackingBehavior = NoTracking。但这适用于获取数据的过程。

希望这会有所帮助。我借助此链接http://andreyzavadskiy.com/2016/09/23/entries-in-entity-framework-changetracker-could-degrade-database-write-performance/?unapproved=19301&moderation-hash=4acc61a32ead7232959c2ec1ca268180#comment-19301

找到了解决方案

答案 2 :(得分:0)

根据Chintan shah的答案,我做了一个extension method和一个例子。

public static class DbContextExtensions
{
    /// <summary>
    /// Set all entries in ChangeTracker to detached to get them collected by the GC
    /// </summary>
    /// <param name="context"></param>
    public static void DetachAllEntriesInChangeTracker(this DbContext context)
    {
        try
        {
            foreach (var entityEntry in context.ChangeTracker.Entries())
            {
                entityEntry.State = EntityState.Detached;
            }
        }
        catch (Exception e)
        {
            LogManager.GetLogger(context.GetType().FullName).Error(e, "error when detaching all entries in changeTracker");
        }
    }
}
public class FooDbContext : DbContext
{
    public override void Dispose()
    {
        this.DetachAllEntriesInChangeTracker();
        base.Dispose();
    }
}