为什么处理实体上下文不能释放内存
本文关键字:释放 内存 不能 上下文 处理 实体 为什么 | 更新日期: 2023-09-27 18:26:05
在我的测试中,我逐行读取文本文件,并插入一个实体和其他相关实体。问题是当插入太多时,我会收到内存不足的异常。
为了防止这种情况,我为每50行创建一个新的DbContext,并处理掉旧的DbContext。我的理解是,这将从早期的实体操作中释放内存,但内存会继续攀升,如果文件足够大,就会发生内存不足异常。这与实体代码有关,就好像我删除了添加实体的代码行一样——内存保持一致的使用。
下面是我的代码的简化版本。
public class TestClass
{
public void ImportData(byte[] fileBytes)
{
using (Stream stream = new MemoryStream(fileBytes))
{
TextFieldParser parser = new TextFieldParser(stream);
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (!parser.EndOfData)
{
//Processes 50 lines creates a new DbContext each time its called
ImportBatch(parser);
}
}
}
public void ImportBatch(TextFieldParser parser)
{
using(myDbContext context = new myDbContext())
{
context.Configuration.AutoDetectChangesEnabled = false;
int batchCount = 0;
while (!parser.EndOfData && batchCount < 50)
{
string[] fields = parser.ReadFields();
//Here I call some code that will add an entity and add releated entities
//In its navigation properties
MyService.AddMyEntity(fields,myDbContext);
batchCount++;
}
myDbContext.ChangeTracker.DetectChanges();
myDbContext.SaveChanges();
}
}
}
当我每50次插入就处理和创建一个新的上下文时,我希望内存使用率保持不变,但在前两千行中似乎是不变的,但在那之后,内存不断攀升,单位为OutOfMemory异常。
以以下方式处理dbContext不会导致内存释放,这是有原因的吗?
EDIT-添加了我的添加实体方法的一些简化代码
public void AddMyEntity(string[] fields, MyDbContext, myDbContext)
{
MyEntity myEntity = new MyEntity();
newRequest.InsertDate = DateTime.UtcNow;
newRequest.AmendDate = DateTime.UtcNow;
//If I remove this line the memory does not consistently climb
myDbContext.MyEntities.Add(myEntity);
foreach(string item in fields)
{
ReleatedEntity releatedEntity = new ReleatedEntity();
releatedEntity.Value = item;
newRequest.ReleatedEntities.Add(releatedEntity);
}
}
另一个编辑
经过更多的测试,这与Glimpse探查器有关。我已经在我的项目中包含了Glimpse,web配置有一个类似于下面的部分。
<glimpse defaultRuntimePolicy="On" endpointBaseUri="~/Glimpse.axd">
<tabs>
<ignoredTypes>
<add type="Glimpse.Mvc.Tab.ModelBinding, Glimpse.Mvc5"/>
<add type="Glimpse.Mvc.Tab.Metadata, Glimpse.Mvc5"/>
</ignoredTypes>
</tabs>
<inspectors>
<ignoredTypes>
<add type="Glimpse.Mvc.Inspector.ModelBinderInspector, Glimpse.Mvc5"/>
</ignoredTypes>
</inspectors>
将defaultRuntimePolicy设置为"关闭"修复了内存泄漏问题。仍然不确定为什么
在对象上调用Dispose
并不一定会释放内存。当对象不再被任何活动对象引用时,垃圾收集器会从内存中删除这些对象。调用Dispose
可能会释放其他资源(例如,在DbContext
的情况下,通过关闭打开的SQL连接),但只有当对象不再被引用时,它才会成为垃圾收集的候选者。
不能保证垃圾收集器会在特定的时间点运行。调用Dispose
当然不会导致它运行。话虽如此,我很惊讶它在你耗尽记忆之前不会运行。您可以强制它使用GC.Collect
运行,但这确实没有必要。
您可能仍然有对上下文对象的引用,这导致它们不符合垃圾收集的条件。例如,您将myDbContext
传递给服务层中的AddEntity
方法——这是否存储了包含对上下文的反向引用(甚至是间接引用)的内容?
因为无论何时调用ImportBatch(解析器),它都会创建一个新的DbContext。每个50不是1个DbContext。您可以尝试使用get属性进行计数,并将上下文返回给您。类似这样的东西:
int _batchCount = 0;
public myDbContext _db;
public myDbContext Db
{
get
{
// If batchCount > 50 or _db is not created we need to create _db
if (_db == null || _batchCount > 50)
{
// If db is already created _batchcount > 50
if (_db != null)
{
_db.ChangeTracker.DetectChanges();
_db.SaveChanges();
_db.Dispose();
}
_db = new myDbContext();
_db.Configuration.AutoDetectChangesEnabled = false;
_batchCount = 0;
}
batchCount++;
return _db;
}
}
此外,在MyService.AddMyEntity(fields);
中,您使用的是MyService
类中的DbContext,而不是在使用行中创建的DbContext。