在将新对象插入数据库时,实体框架似乎使用了过多的内存。
for(int i = 0; i < numOwners; ++i)
{
var owner = Owner.CreateOwner();
db.AddToOwnerSet(owner);
for(int j = 0; j < numChildren; ++j)
{
var child = Child.CreateChild();
owner.Childs.Add(child);
}
}
db.SaveChanges();
此时,这些对象包含的数据元素非常少。将140,000个这些对象插入数据库时,应用程序的总内存使用量为600 MB,而300,000的内存使用量为1.2 GB。这些对象很小,只是一个字符串名称和一个整数键。
我可以通过将SaveChanges调用放入循环来减少内存使用量,但是执行时间会变得更糟,而且已经非常糟糕了。
任何人都知道为什么实体框架使用了这么多内存,或者如何让它使用更少的内存?
答案 0 :(得分:2)
由于实体框架将数据保存在内存中(与许多ORM一样),因此与许多内存中的集合一样,可能存在内部数组。在向集合中添加项目时,内部数组的容量会增加一倍。
例如,如果你有一个类似于包含256个项目的ArrayList的集合,并将第257个项目添加到它,那么内部发生的是为512个项目数组分配的新内存块,它们会复制256个项目数组到新的512项数组,然后256项数组可用于垃圾回收。因此,在转换点,您将在内存中分配768个项目,因为您添加了第257个项目。使用内存流时,我遇到了令人头疼的问题,因为你需要的内存碎片内存几乎是你真正需要的3倍。这是您在集合上看到的.Capacity属性,它几乎总是2的幂(因为它根据需要增加了一倍)。
我敢打赌,内部数组的大小可以根据需要加倍,以支持内存对象的集合。因此,相同类型的300,000个对象可能会保存在大小为524,288的内部数组中。另外,如果它类似于.NEt框架中的其他类似技术,那么每当添加262145项时,内存中都存在262144和524288数组,而项目被复制到新数组。内存中共有786432项。旧阵列会一直存在,直到垃圾收集器决定不再需要它为止。
实体框架中可能存在一些关于可以禁用的并发支持的选项,这可能会提高内存使用率。我只是在这里推测,但是为了支持并发,它们在内存中存储当前版本的数据,并且它是用于比较的原始版本以支持并发。
我还会考虑过滤您正在与之交互的数据。尝试找到聪明的标准来限制查询和加载到内存中的内容。例如,如果您的应用程序允许用户编辑客户帐户,但仅为其分配了某些帐户,则将其用作过滤条件,以便您只在内存中加载用户可能与之交互的帐户。
答案 1 :(得分:2)
我知道这是一个老问题,但我今天遇到了同样的问题,并设法找出导致它的原因!
看起来SQL脚本的生成是造成内存大幅跳跃的原因。我发现创建存储过程并将它们链接到我的对象(但确保返回this article中显示的id的值)为我节省了超过300mb的内存。
答案 2 :(得分:1)
您的对象在实际数据方面可能“小”,但每个对象不是DTO - 实体框架会为您的每个实体附加大量样板代码,这意味着每个对象的实际大小非常大
如果您一直在使用大型对象图,请考虑使用NHibernate之类的东西,它是稳定的,成熟的并且经过验证可行。实体框架在功能和性能方面远远落后。