我使用EF有一个非常简单的应用程序。但是当它运行一周时,内存使用率很差(一开始只有80MB,一周后只有700MB)。 当我使用dotMemory来配置我的应用程序时。我发现Heap第2代的记忆一直在增加。
我得到一个快照,最后发现ef dbcontext的保留字节是最多的。
我很困惑。我的申请很简单。代码示例:
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;
但这些不起作用。
答案 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
。但这适用于获取数据的过程。
答案 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();
}
}