内存泄漏实体框架

时间:2012-07-12 11:32:33

标签: c# .net entity-framework entity-framework-4 sql-server-ce

我在使用带有SQL Server Compact Edition的Entity Framework时出现内存泄漏。我的情况:

我有一个大约600MByte的文件。我逐行阅读,创建一个实体类并将其添加到SQL Server CE数据库。内存的增长速度非常快。 Gen 0集合计数器和Gen 2堆大小增长非常快(来自Process Explorer的信息)。如果我理解正确的Gen 2堆是用于大对象。我认为我的实体类是一个大对象。因此,实体框架保存我的对象而不释放它们。我已经尝试分离它们并调用GC.Collect(2)但它没有帮助。

首先我读了这行。然后在解析该行后创建一个对象。然后将其添加到DB。这是我的数据库代码:

DBEntities dbConnection = new DBEntities();
dbConnection.My_Table.AddObject(MyObjectCreatedFromTheLine);
dbConnection.SaveChanges();
//  dbConnection.Detach(MyObjectCreatedFromTheLine);
//  dbConnection.Dispose();
MyObjectCreatedFromTheLine = null;
dbConnection = null;

我还读到创建的实体类(MyObjectCreatedFromTheLine)属于DbContext。所以我为每一行调用这段代码,每次都创建一个新的上下文。

我做错了什么?

4 个答案:

答案 0 :(得分:4)

我遇到了这个问题,尝试使用实体框架将50,000多条记录插入到SQL数据库中。实体框架不适用于大量的批量操作(大型插入或删除操作),因此我最终使用了System.Data.SqlClient.SqlBulkCopy库,它更有效,更快捷。我甚至将下面的辅助函数编写为自动映射,因此我不必手动构造SQL Insert语句。 (它的边缘类型独立!我认为)。

基本上工作流程是:IList< MyEntityType> - > DataTable - > SqlBulkCopy的

public static void BulkInsert<T>(string connection, string tableName, IList<T> list)
    {
        using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepNulls))
        {
            bulkCopy.BatchSize = list.Count;
            bulkCopy.DestinationTableName = tableName;
            bulkCopy.BulkCopyTimeout = 3000;

            var table = new DataTable();
            var props = TypeDescriptor.GetProperties(typeof(T))
                //Dirty hack to make sure we only have system data types 
                //i.e. filter out the relationships/collections
                                       .Cast<PropertyDescriptor>()
                                       .Where(propertyInfo => propertyInfo.PropertyType.Namespace.Equals("System"))
                                       .ToArray();

            foreach (var propertyInfo in props)
            {
                bulkCopy.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name);
                table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType);
            }

            var values = new object[props.Length];
            foreach (var item in list)
            {
                for (var i = 0; i < values.Length; i++)
                {
                    values[i] = props[i].GetValue(item);
                }

                table.Rows.Add(values);
            }

            bulkCopy.WriteToServer(table);
        }
    }

在我的例子中,我从15-20分钟开始插入到不到一分钟。

答案 1 :(得分:0)

我认为你的方法不对。只需创建一个DBEntities对象即可保存所有更改。以下内容可能有效;

using(DBEntities dbConnection = new DBEntities())
{
    foreach(MyObjectCreatedFromTheLine entity in ListOfMyObjectCreatedFromTheLine)
    {
        dbConnection.My_Table.AddObject(MyObjectCreatedFromTheLine);
    }
    dbConnection.SaveChanges();
}

您正在创建一个新的DBEntities对象foreach实体,这是不对的。只是将dbConnection设置为null并不意味着该对象被丢弃或垃圾收集器不会收集它。实际上,您只是将引用设置为null,该对象仍然在内存中,垃圾收集器将收集该对象。

答案 2 :(得分:0)

我不认为通过数据上下文添加大量实体是最好的方法。对于每个创建的对象,您使用内存,因为数据上下文具有内部第一级缓存,其中对象保留直到上下文被处理。

我不太熟悉EF,也不知道每次持久保存单个对象时是否可以清除缓存。但是,我宁愿选择不使用EF来执行大量插入。

相反,请使用SqlBulkCopy类。它应该可以解决您的内存问题,并且比使用EF和每个对象插入可以实现的任何速度快一个数量级。

答案 3 :(得分:0)

让你的DBEntities dbConnection =新的DBEntities()离开循环!?

在每次迭代中创建新的对象上下文都是无关紧要的,因为它太荒谬了。

此外,分配需要更多时间,特别是对于像这样的大型对象,更不用说内存开销和释放可能是问题。