Asp.net EF缓存:如何在将对象插入HttpRuntime缓存之前完全分离对象? 一些背景:
使用:Asp.net EF缓存:如何在将对象插入HttpRuntime缓存之前完全分离对象? 一些背景:,asp.net,entity-framework,caching,memory-leaks,entity-framework-5,Asp.net,Entity Framework,Caching,Memory Leaks,Entity Framework 5,使用: .NET4.5(如果没有痛苦,考虑迁移到4.5.1) 网络表单 实体框架5,启用延迟加载 每个请求的上下文 IIS 8 Windows 2012数据中心 关注点:内存使用 在我们目前正在进行的项目中,可能是我们的第一个更大的项目,我们经常读取来自CSV导入的更大数据块,这些数据可能会在很长一段时间内保持不变 除非有人明确地重新导入CSV数据,否则它们保证是相同的,这在我们项目中的多个地方都会发生,并且对于用户经常阅读的一些常规文档,也会使用类似的方法。我们已决定将此数据缓存在Http
- .NET4.5(如果没有痛苦,考虑迁移到4.5.1)
- 网络表单
- 实体框架5,启用延迟加载
- 每个请求的上下文
- IIS 8
- Windows 2012数据中心
//myObject and related methods are placeholders
public static List<myObject> GetMyCachedObjects()
{
if (CacheManager.Exists(KeyConstants.keyConstantForMyObject))
{
return CacheManager.Get(KeyConstants.keyConstantForMyObject) as List<myObject>;
}
else
{
List<myObject> myObjectList = framework.objectProvider.GetMyObjects();
CacheManager.Add(KeyConstants.keyConstantForMyObject, myObjectList, true, 5000);
return myObjectList;
}
}
//myObject和相关方法是占位符
公共静态列表GetMyCachedObjects()
{
if(CacheManager.Exists(KeyConstants.keyConstantForMyObject))
{
以列表形式返回CacheManager.Get(KeyConstants.keyConstantForMyObject);
}
其他的
{
List myObjectList=framework.objectProvider.GetMyObjects();
CacheManager.Add(KeyConstants.keyConstantForMyObject,MyObject列表,true,5000);
返回myObjectList;
}
}
上述方法的数据检索非常简单,如下所示:
public List<myObject> GetMyObjects()
{
return context.myObjectsTable.AsNoTracking().ToList();
}
public List GetMyObjects()
{
返回context.myObjectsTable.AsNoTracking().ToList();
}
关于代码结构可能有一些事情要说,但这不是我目前关心的
当我发现内存使用率很高,并且发现许多代码可以优化的地方时,我就开始分析我们的项目。我以前从未同时面对过300个用户,我们自己做的内部测试不足以显示内存问题。我强调并修复了大量内存泄漏,但我想了解一些与实体框架相关的未知数
在上面的例子中,使用ANTS Profiler,我注意到“myObject”和其他类似的对象引用了许多System.Data.Entity.DynamicProxies.myObject,另外还有许多EntityKey,它们保存着整数。他们拿的不多,但数量相对较高
例如,“myObject”的124个实例引用了近300个System.Data.Entity.DynamicProxies
无论对象是什么,通常都是这样的:
一些缓存条目,一些我缓存过的对象,我现在注意到其中许多已经从dbContext之前的缓存、动态代理和objectContext中分离出来。我不知道如何解开它们
我的进度:
我做了一些研究,发现我可能正在缓存与这些对象相关的实体框架。我用NoTracking提取了它们,但记忆中仍然有那些动态的线索,它们可能也会保留其他东西
重要提示:我观察到ObjectContext(74)的一些活动实例正在缓慢增长,但没有持有dbContext的unitOfWork实例。这些似乎是根据每个请求正确处理的
我知道如何从dbContext中分离、附加或修改条目的状态,dbContext封装在unitOfWork中,我经常这样做。然而,这似乎还不够,或者我要求的是不可能的
问题:
- 基本上,当涉及实体框架时,我的缓存方法有什么错
- 内存中越来越多的对象上下文是一个问题吗?我知道缓存最终会过期,但我担心打开的连接或此上下文可能包含的任何其他内容
- 我应该在将内容插入缓存之前将其与上下文分离吗
- 如果是,最好的方法是什么。尤其是对于List,除了遍历集合并逐个调用detach之外,我想不出其他任何事情
- 附加问题:大约40%的消耗内存是空闲的(未分配的),我不知道.NET为什么要提前保留这么多空闲内存
public class MyObject2 {
public int ID { get; set; }
public string Name { get; set; }
}
public List<MyObject2> GetObjects(){
return framework.provider.GetObjects().Select(
x=> new MyObject2{
ID = x.ID ,
Name = x.Name
}).ToList();
);
}
公共类MyObject 2{
公共int ID{get;set;}
公共字符串名称{get;set;}
}
公共列表GetObjects(){
返回framework.provider.GetObjects()。选择(
x=>新的MyObject 2{
ID=x.ID,
Name=x.Name
}).ToList();
);
}
因为您将存储普通的c#对象,所以不必担心动态代理。您根本不必调用detach。此外,您只能存储少数属性
即使您禁用跟踪,您也会看到动态代理,因为EF使用从您的类派生的动态类,该类存储实体的额外元数据信息(例如,外键名称等与其他实体的关系)。此处减少内存的步骤:
- 重新
上下文,通常 不要尝试从上下文中删除内容。或者将其设置为“分离”。 它就像放在电话盒里的屁一样到处乱放new
例如context=newmycontext.
但如果可能的话,你应该
//短期上下文是最佳实践
- 根据您的上下文,您可以设置配置
this.Configuration.LazyLoadingEnabled=false;
this.Configuration.ProxyCreationEnabled=false// 我会重新设计一下解决方案:
- 您将所有数据作为一个条目存储在缓存中
我将移动此项,并为每个缓存项创建一个条目<
this.Configuration.LazyLoadingEnabled = false;
this.Configuration.ProxyCreationEnabled = false; //<<<<<<<<<<< THIS one
this.Configuration.AutoDetectChangesEnabled = false;