如何在创建对象时避免EntityFramework中的内存泄漏? [英] How can I avoid memory leak in EntityFramework at object creation?

查看:198
本文介绍了如何在创建对象时避免EntityFramework中的内存泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,



我是EntityFramework的新手,我遇到了一个问题,当我向数据库添加多个项目时。

这不是真正的应用程序,但出于学习目的,我创建了一个测试应用程序,它模拟了真实应用程序的行为。



真正的应用程序是基于生产者 - 消费者模式,消费者在某处保存接收的字节数组 - 带有一些元数据 - 这是在用户交互时创建的,因此我不知道何时以及有多少来自。



要模拟这种模式,这是我创建的代码:



Hello everybody,

I'm quite newbie to EntityFramework and I have encountered a problem, when I add multiple items to database.
This is not the real application, but for learning purposes I have created a test app, that kinda simulate the behaviour of the real application.

The real application is based on producer-consumer pattern, where the consumer saves the received array of bytes somewhere - with some metadata -, which is created upon user interaction, so I don't know when and how many comes.

To simulate this pattern, this is the code I created:

private void Button_Click_1(object sender, RoutedEventArgs e)
       {
           string filename = @"path-to-a-jpg";

           //approx. 15 megabytes of Bmp image, to fill up the DB more quickly
           byte[] data = System.Drawing.Image.FromFile(filename).ToByteArray();

           Visitor someone;

           for (int i = 0; i < 100; i++)
           {
               using (ZooContext ctx = new ZooContext())
               {
                   someone = new Visitor()
                   {
                       Name = "test100 " + i,
                       Img = data
                   };


                   ctx.Visitors.Add(someone);

                   ctx.SaveChanges();//around 81 it crashes with out of memory exception

                   someone = null;
               }

               GC.Collect();//tried to force garbage collection, but it didn't help
           }
       }





Class,存储在数据库中(保持延迟加载会很好):





Class, that is stored in the DB (it would be nice, to keep the lazy loading enabled):

public class Visitor
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public byte[] Img { get; set; }

        public virtual ICollection<Animal> FavouriteAnimals { get; set; }
    }





我的DbContext是这个类:



My DbContext is this class:

public class ZooContext : DbContext
    {
        public ZooContext()
        {
            //we disable databese initialization
            Database.SetInitializer<ZooContext>(new System.Data.Entity.NullDatabaseInitializer<ZooContext>());

        }

        public DbSet<Animal> Animals { get; set; }

        public DbSet<Visitor> Visitors { get; set; }


        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            //i just need the singular class names as tabel names
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

            modelBuilder.Entity<Visitor>()
                .HasMany(v => v.FavouriteAnimals)
                .WithMany(a => a.Visitors)
                .Map(m =>
                {
                    m.MapLeftKey("Visitor_ID");
                    m.MapRightKey("Animal_ID");
                    m.ToTable("Visitor_Animal");
                });


            base.OnModelCreating(modelBuilder);
        }

    }





添加约。 80个项目抛出OutOfMemory异常,此时任务管理器显示大约1200兆字节的已用内存,用于包含我的应用程序的vshost进程。

我在32GB的3GB计算机上测试它RAM,但我认为内存开销应该少得多。



顺便说一句,从如此庞大的数据库中检索是可以的,因为它对我来说没问题,检索到的对象没有被跟踪,查询图像的内存开销很小,我的DB现在大约是11GB :)。



我忘了添加,我使用SQLite和System.Data.SQLite提供程序。



提前致谢!我感谢任何建议。



After adding approx. 80 items it throws an OutOfMemory exception and at that point the task manager shows around 1200 megabytes of used memory, for vshost process containing my application.
I'm testing it on a 32-bit computer with 3GBs of RAM, but I suppose that the memory overhead should be much more less.

By the way, retrieving from such a huge DB is OK, because it's OK for me, that the retrieved objects are not tracked and querying for images has little memory overhead even, my DB is around 11GB now :).

I forgot to add, that I'm using SQLite with System.Data.SQLite provider.

Thanks in advance! I appreciate any suggestion.

推荐答案

而不是通过类全局使用上下文,在中为<创建上下文的实例/ code>循环,让您的数据库为该记录工作并保存,然后处理上下文实例。对循环的每次迭代重复。



问题是你将某人设置为null但是访问者实例不会消失。原因是因为EF更改跟踪器仍然保持对您添加的对象的引用,甚至跟踪其中属性的原始值。



处理实例上下文并在每个传递中创建一个新的也会杀死上下文中的更改跟踪器并删除对您添加的对象的引用,释放它们以便垃圾收集器执行它的操作。



你根本不需要调用GC.Collect。



你的设计的一个问题是,如果你试图获得对于某些查询的所有访客记录,您将返回大约15MB的EACH RECORD数据。这不是一个可扩展的解决方案。如果您想要每个访客的数据而不是图片,那么您不能使用当前的设计。请参见 [ ^ ]以获取将表拆分为两个类的示例。这使您可以在不挖掘所有图像数据的情况下处理所有数据。



我在当前项目中对图像使用了类似的技术。我使用一个类存储所有图像元数据和缩略图数据,使用单独的类存储全尺寸图像数据,这两个类都映射到同一个数据库表。像魅力一样工作。
Instead of using a context "globally" through the class, create an instance of the context inside your for loop, do your database work for that record and save, then dispose of the context instance. Repeat for every iteration of the loop.

The problem is that you set someone to null but the Visitor instance does not go away. The reason is because the EF change tracker is still holding a reference to the objects you added and is even tracking original values for the properties in them.

Disposing the instance of the context and creating a new one on every pass also kills the change tracker inside the context and drops the references to the objects you added, freeing them up for the garbage collector to do its thing.

You don't need the call to GC.Collect at all.

One of the problems with your design is that if you tried to get all of Visitor records for some query you'd be returning about 15MB of data for EACH RECORD. That isn't a scalable solution. If you want the data on every Visitor but not the pictures you con't do that with your current design. See this[^] for an example of splitting the table into two classes. This allows you to work with all of the data without digging up all of the image data.

I used a similar technique for images in my current project. I store all the image metadata and thumbnail data using one class and the full size image data using a separate class, both of which are mapped to the same database table. Works like a charm.


这篇关于如何在创建对象时避免EntityFramework中的内存泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆