[英]ObjectContext is leaking memory for detached entities
我已经使用内存分析器进行了检查,并且没有真正的实体保留在内存中, 而是散列集,字典和EntityKey对象-但我找不到办法断开这些引用的连接。
如此简单的问题:如何阻止上下文(或其ObjectStateManager)的大小无限增长 ?
[是的,我知道应该避免使用长寿的上下文,但是在这种情况下,这是一次复杂的分析,需要加载多个层次结构数据(下面的示例只是一个最小的问题演示),所以最后这是一个“简短的”生活的单一操作环境。]
复制步骤:
代码[已更新,不再需要真正的数据库连接]:
class Program
{
static void Main()
{
const double MiB = 1024 * 1024;
using ( var context = new NorthwindEntities() )
{
var last = GC.GetTotalMemory(true) / MiB;
Console.WriteLine("before run: {0:n3} MiB", last);
var id = 0;
while ( true )
{
Run(context, ref id);
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
var current = GC.GetTotalMemory(true) / MiB;
Console.WriteLine("after run: {0:n3} MiB (+{1:n3} MiB)", current, current - last);
last = current;
if ( Console.KeyAvailable )
break;
Console.WriteLine(new string('-', 100));
}
}
}
static void Run(NorthwindEntities context, ref int id)
{
for ( int i = 0; i < 100000; i++ )
{
var category = new Category { Category_ID = ++id };
category.EntityKey = new EntityKey("NorthwindEntities.Categories", "Category_ID", id);
var product = new Product { Product_ID = id, Category_ID = id };
product.EntityKey = new EntityKey("NorthwindEntities.Products", "Product_ID", id);
product.Category = category;
context.Attach(product);
context.Detach(product);
context.Detach(category);
}
var ctr = 0;
Console.WriteLine("Enumerating living/attached objects:");
const EntityState AllStates = EntityState.Added | EntityState.Deleted | EntityState.Modified | EntityState.Unchanged;
foreach ( var entry in context.ObjectStateManager.GetObjectStateEntries(AllStates) )
Console.WriteLine(" #{0} [{1}] {2}", ++ctr, entry.EntityKey, entry.Entity);
if ( ctr == 0 )
Console.WriteLine(" NOTHING (as expected)");
}
}
由于仅在调用SaveChanges()之后才直接分离实体,所以现在要计算分离的实体的数量,当计数器达到10,000时,我将从上下文中分离所有仍在运行(和需要)的对象,并创建新的上下文以我附加了所有分离的对象。 缺点:EntityReferences和EntityCollections的IsLoaded属性现在始终为false(但我不依赖于此)。
我的理解是,分离是指从实体中删除上下文,而不是从上下文中删除实体。 不要相信上下文会删除对实体(或其内部)的引用。
我同意这种泄漏是一个问题,但是很多人(包括我自己在内)尝试并未能阻止EF上下文无限期地增长(只要正在运行查询)。
作为一种建议的解决方案,也许不必依赖数据库作为计算的“工作空间”,而是可以用自己的内存表示形式重新创建数据库结构,进行处理,然后再转换回db。 如果您有大量数据,则可以使用临时文件。
这应具有缩短上下文寿命的效果。
或者,也许考虑使用除EF以外的其他东西(至少用于处理密集型零件),因为它可能不适合您的情况。 也许像DataReader这样的较低级别的东西更适合您的情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.