关于 Linq to EF 的内存泄漏问题
2014-01-24 18:23
573 查看
查到一些解决方案:
1, http://www.codethinked.com/keep-your-iqueryable-in-check
自定义常用方法,屏蔽IQuery功能。这个好像有点靠谱。但麻烦。
2,http://stackoverflow.com/questions/123057/how-do-i-avoid-a-memory-leak-with-linq-to-sql
这个看起来是应对 ObjectContext的。
3,http://stackoverflow.com/questions/19116851/entity-framework-using-repository-pattern-unit-of-work-and-unity
这个看起来简单些 ,用using.
4, 直接用using的方式
using(dbcontext)
{
}
5, http://blog.robustsoftware.co.uk/2008/11/clearing-cache-of-linq-to-sql.html
这个针对 DataContext的一个扩展方法。
最后没有更好的解决办法。
/******************************Edit 2014-1-25**************************************************************/
最后在分析了DbContext的源代码以后,发现了其中的奥秘。
首先DbContext本身是对于ObjectContext的一个包装,在使用IQueryable以后会将Enitiy存于 objectStateManager ,在快速的循环中,_unchangedEntityStore不会被释放,一直被缓存,所以呢?你会发现程序的内存在不断的上涨,这不应该算是内存泄漏。 由于 _unchangedEntityStore 中的值变得越来越大,程序在查询前先去 _unchangedEntityStore 中查找,由于Dictionary<EntityKey, EntityEntry> 在很大的情况下,查询性能会急剧下降,所以程序变慢。 直到慢得你无法忍受。
下面是基本代码。
[/code]
然后发现内存还是疯长。
那就再加一个方法。
[/code]
再看内存,
这样世界顿时安静了下来。
最后说明:
这个方法的确不是一个好的办法,但是由于EF的对象管理机制决定。 人家缓存也有人家缓存的道理。
实际上MS也没有打算让你按这样的方法来用,
用using(dbcontext)
{
…..
}
这样的方式反而是保持了 Kiss。
对于这样的“改进” 会不会有什么影响呢?
这个就再开个文章再来测试了。
1, http://www.codethinked.com/keep-your-iqueryable-in-check
自定义常用方法,屏蔽IQuery功能。这个好像有点靠谱。但麻烦。
2,http://stackoverflow.com/questions/123057/how-do-i-avoid-a-memory-leak-with-linq-to-sql
这个看起来是应对 ObjectContext的。
3,http://stackoverflow.com/questions/19116851/entity-framework-using-repository-pattern-unit-of-work-and-unity
这个看起来简单些 ,用using.
4, 直接用using的方式
using(dbcontext)
{
}
5, http://blog.robustsoftware.co.uk/2008/11/clearing-cache-of-linq-to-sql.html
这个针对 DataContext的一个扩展方法。
最后没有更好的解决办法。
/******************************Edit 2014-1-25**************************************************************/
最后在分析了DbContext的源代码以后,发现了其中的奥秘。
首先DbContext本身是对于ObjectContext的一个包装,在使用IQueryable以后会将Enitiy存于 objectStateManager ,在快速的循环中,_unchangedEntityStore不会被释放,一直被缓存,所以呢?你会发现程序的内存在不断的上涨,这不应该算是内存泄漏。 由于 _unchangedEntityStore 中的值变得越来越大,程序在查询前先去 _unchangedEntityStore 中查找,由于Dictionary<EntityKey, EntityEntry> 在很大的情况下,查询性能会急剧下降,所以程序变慢。 直到慢得你无法忍受。
下面是基本代码。
[code]public class Class1
{
public static void Test()
{
Domain.Entities.Models.passportContext context =
new Domain.Entities.Models.passportContext("passportContext");
context.Configuration.ProxyCreationEnabled = false;
context.Configuration.LazyLoadingEnabled = false;
var start = int.MaxValue;
var om = ((IObjectContextAdapter)context).ObjectContext.ObjectStateManager;
om.ObjectStateManagerChanged += om_ObjectStateManagerChanged;
while (true)
{
var list = context.UserSources.OrderByDescending(x => x.UserId).Where(x => x.UserId < start).Take(100).ToList();
ObjectContext oc = ((IObjectContextAdapter)context).ObjectContext;
var m = oc.ObjectStateManager;
var a = list.First();
var count = GetUnchangedCount(context);
var mth = m.GetType().GetMethod("GetObjectStateEntriesCount", BindingFlags.Instance | BindingFlags.NonPublic);
var unchanged = mth.Invoke(m, new object[]{ EntityState.Unchanged});
if (a.UserId % 4 == 0)
{
a.FromSite += 1;
context.Entry(a).State = System.Data.EntityState.Modified;
}
count = GetUnchangedCount(context);
ClearUnchangedCache(context);
Console.WriteLine(a.UserId);
//ClearCache(context);
start = a.UserId;
}
}
static void om_ObjectStateManagerChanged(object sender, System.ComponentModel.CollectionChangeEventArgs e)
{
Console.WriteLine("[]" + e.Action + "" + e.Element.GetType() + "::" + e.Element);
}
public static void ClearCache(DbContext context)
{
ObjectContext oc = DbContext2ObjectContext(context);
const BindingFlags flags = BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance;
var c = oc.GetType().GetField("_cache", flags);
//var value = c.GetValue(oc);
c.SetValue(oc, null);
//value = c.GetValue(oc);
}
static int GetUnchangedCount(DbContext context)
{
var objectStateManager = DbContext2ObjectStateManager(context);
var mth = objectStateManager.GetType().GetMethod("GetObjectStateEntriesCount", BindingFlags.Instance | BindingFlags.NonPublic);
var unchanged = mth.Invoke(objectStateManager, new object[]{ EntityState.Unchanged});
return (int)unchanged;
}
static ObjectContext DbContext2ObjectContext(DbContext context)
{
return ((IObjectContextAdapter)context).ObjectContext;
}
static ObjectStateManager DbContext2ObjectStateManager(DbContext context)
{
return DbContext2ObjectContext(context).ObjectStateManager;
}
static void ClearUnchangedCache(DbContext context)
{
var objectStateManager = DbContext2ObjectStateManager(context);
const BindingFlags flags = BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance;
var c = objectStateManager.GetType().GetField("_unchangedEntityStore", flags);
c.SetValue(objectStateManager, null);
}
}
[/code]
然后发现内存还是疯长。
那就再加一个方法。
[code]static void ClearKeylessEntityCache(DbContext context)
{
var objectStateManager = DbContext2ObjectStateManager(context);
const BindingFlags flags = BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance;
var c = objectStateManager.GetType().GetField("_keylessEntityStore", flags);
c.SetValue(objectStateManager, null);
}
[/code]
再看内存,
这样世界顿时安静了下来。
最后说明:
这个方法的确不是一个好的办法,但是由于EF的对象管理机制决定。 人家缓存也有人家缓存的道理。
实际上MS也没有打算让你按这样的方法来用,
用using(dbcontext)
{
…..
}
这样的方式反而是保持了 Kiss。
对于这样的“改进” 会不会有什么影响呢?
这个就再开个文章再来测试了。
相关文章推荐
- 关于创建 LINQ to SQL 类时无法转换复数的问题(zhuan)
- LINQ to Entities中关于类型转化的问题
- LINQ to EF容易疏忽的几个小问题
- 关于linq to sql调用存储过程,出现"无法枚举查询结果多次"的问题
- Linq To EF 使用小知识(添加记录后获取添加的自增ID和叫“ID”的列不是自增列不让插入的问题)
- Linq To EF 用泛型时生成的Sql会查询全表的问题
- 关于Linq to sql的一个更新问题
- EF架构~linq to entity的随机排序问题
- 关于linq to sql调用存储过程,出现"无法枚举查询结果多次"的问题
- 关于使用Linq to sql作为数据交互时的架构问题
- 关于LINQ TO SQL (dbml文件)的更新问题
- 关于Linq to sql更新的问题
- Linq To EF 使用小知识(添加记录后获取添加的自增ID和叫“ID”的列不是自增列不让插入的问题)
- linq to sql更新问题解决方案
- 一个关于wwf和linq的部署问题?
- 关于org.apache.jasper.JasperException: Unable to compile class for JSP问题的解决方案
- 关于LIST.Select().ToList()慢的问题
- linq to sql 学习(5)关于排序的介绍
- Flex 问题_关于unable to open
- [分享] 关于 iframe 内存泄漏问题