【发布时间】:2011-11-29 13:40:21
【问题描述】:
我已经使用内存分析器检查了这一点,并且没有真正的实体留在内存中但是散列集、字典和 EntityKey 对象——但我发现无法断开这些引用。
这么简单的问题:如何阻止上下文(或其 ObjectStateManager)的大小无限增长?
[是的,我知道应该避免长期存在的上下文,但在这种情况下,这是一个复杂的分析运行,需要加载多个分层数据(下面的示例只是一个最小的问题演示)所以最后这是一个“短暂”的单操作上下文。]
复制步骤:
- 创建一个新的控制台应用程序
- 为 Northwind 数据库创建 EF 模型(使用一些真正的 SQL Server 或从 Compact Samples 文件夹复制 Northwind.sdf)
- 使用以下代码:
代码[已更新,不再需要真正的数据库连接]:
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)");
}
}
【问题讨论】:
-
好的,你的结果是什么?您是否使用了内存分析器?
-
运行多少次以及多少分钟才能达到 0.1 / 0.5 / 1.0 / 1.5 GB?
-
@Henk Holterman:是的,我使用了内存分析器,只看第一句话。我的示例使用 SQL Server Compact 的性能非常差,但真正的应用程序使用的是 SQLite,它可以在 10% 的时间内在每个
SaveChanges()上保存 10,000 个新实体,因此很快就浪费了一个完整的 1 GiB不求回报。此处的示例每次运行损失约 0.5MiB。 -
Fwiw,我确实确认了您之前版本的结果。我认为您应该重构和重新设计以使用寿命较短的上下文。
-
我主要在 ASP.NET 和 WCF 项目中使用分离的对象。该功能用于将对象传输到不同的上下文,而不是手动管理内存。上下文是短暂的,不要与之抗争。
标签: c# .net entity-framework memory-leaks