IQueryable-as-IEnumerable的foreach是否允许对先前迭代的对象进行GC处理/回收?



给定,例如:

IEnumerable<LargeObject> Read(int x) {
    // Implicit IQueryable<LargeObject> -> IEnumerable<LargeObject>
    return ef6Context.LargeObjects.Where(o => o.ObjectType == x);
}
var largeObjects = Read(21281); // Returns "many" objects
// Only use/iteration of IEnumerable result
foreach (var o in largeObject) {
   // When processing the second item (and so on),
   // can the first (previous) "o" object be GC'ed?
   Process(o);
}

是在上面处理的"大对象" 有资格的垃圾回收吗?

答案应涵盖任何内部EF缓存。

实体框架将所有实体都从数据库中检索到上下文中,以便在迭代后不会收集它们。这样做是为了跟踪更改。您可以通过在执行前在查询(文档)之前在查询上调用AsNoTracking来禁用此功能。这样做SaveChanges不会持续对这些实体进行任何更改。

关于天气问题,每次迭代后都会释放对象,答案是肯定的。我创建了一个简单的演示,可以通过在构造函数和Destructor中添加记录代码并添加明确的GC调用来对此进行质量。每次迭代后都会调用破坏者。

public class Program
{
    public static void Main(string[] args)
    {
        using (var db = new MyContext())
        {
            //for (int i = 0; i < 1000; i++)
            //{
            //    db.Enta.Add(new Entity());
            //}
            //db.SaveChanges();
            foreach (var e in db.Enta.AsNoTracking())
            {
                Console.WriteLine(e.Id);
                GC.Collect();
            }
            GC.Collect();
        }
    }
}
public class Entity
{
    public Entity()
    {
        Console.WriteLine("ctor");
    }
    ~Entity()
    {
        Console.WriteLine("destructor");
    }
    public int Id { get; set; }
}
public class MyContext : DbContext
{
    public DbSet<Entity> Enta { get; set; }
}

最新更新