避免实体框架查询返回的列表中的内存泄漏
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了避免实体框架查询返回的列表中的内存泄漏相关的知识,希望对你有一定的参考价值。
我想知道如何确保分配给对象列表的内存将被释放。
我在c#.NET程序中有一个方法,它返回一个根据许多条件过滤的对象列表。编写该方法使得不能在一个查询中执行该过滤,因此在过滤器被细化时它继续重新创建列表。
我坚信这个方法负责一个内存,因为在多次调用此方法之后,用户报告了一个内存不足异常的崩溃。
代码是这样的:
private List<Things> GetMatchingThings(DataContext context, string number,
DateTime startDate, DateTime endDate,
string otherNumber, string orderNumber,
string shiftNumber,
bool includeDeletedThings)
{
List<Things> thingList = context.Set<Things>()
.Where(th => th.Number == number &&
th.FinishDateTime.HasValue &&
!th.IsRunning)
.ToList();
if (thingList != null && thingList.Count > 0 )
{
var filteredList = thingList.FindAll(th => th.StartDateTime.Date >= startDate.Date
&&
th.StartDateTime.Date <= endDate.Date);
thingList = filteredList;
}
if (thingList != null && thingList.Count > 0 && otherNumber.IsNotNullOrEmpty())
{
var filteredList = thingList.FindAll(th => th.OtherNumber.Equals(otherNumber));
thingList = filteredList;
}
if (thingList != null && thingList.Count > 0 && orderNumber.IsNotNullOrEmpty())
{
var filteredList = thingList.FindAll(th => th.orderNumber != null &&
th.orderNumber.Equals(orderNumber));
thingList = filteredList;
}
// Other repetitions of the filtering above for the remaining search criteria
if (thingList != null && thingList.Count > 0)
{
thingList.Sort((x,y) => y.StartDateTime.CompareTo(x.StartDateTime));
}
return thingList;
}
过滤是在这样的阶段完成的,因为某些搜索条件是可选的,只会始终包含开始日期。因此,找到初始列表,然后根据提供的其他标准进一步过滤。
但是,我假设使用FindAll方法调用创建一个新列表,但是当这个新列表分配给thingList时,thingList占用的原始内存不被回收。
据我所知,在创建每个新的filteredList之后调用thingList.Clear()会有所帮助,因为Clear只清除列表中的项目但不回收内存。
Thing对象还包含一个不受管理的属性。
我的问题是我怎么能
a)找到一种方法来释放在中间查询中分配给thingList和filteredList的内存
要么
b)重写原始Where查询,以便一次性执行此操作,因为可能不需要某些搜索条件。是否有一种在SQL中使用通配符的方法,就像在SQL中一样,例如.Where th.orderNumber.Equals(“%”)
C#使用垃圾收集器。如果不再将值分配给任何变量或字段,则GC将收集该值。在上面的代码中,分配的列表(返回的列表除外)将在下一个GC周期中清除。在C#中创建内存“泄漏”相当困难,通常,这意味着您将大量大数据存储在您不想存储的列表中
如果列表包含大量数据,并且您不想一遍又一遍地复制它,则可以使用LINQ:
context.Set<Things>()
.Where(th => th.Number == number && th.FinishDateTime.HasValue && !th.IsRunning)
.Where(th => th.StartDateTime.Date >= startDate.Date && th.StartDateTime.Date <= endDate.Date)
.Where(th => th.OtherNumber.Equals(otherNumber))
.Where(th => th.orderNumber != null && th.orderNumber.Equals(orderNumber))
.OrderBy((x,y) => y.StartDateTime.CompareTo(x.StartDateTime))
.ToList();
请尝试以下操作以排除任何DB / changetracker问题:
//note: renamed dbContext variable
private List<Things> GetMatchingThings(DataContext doNotUseContext, string number,
DateTime startDate, DateTime endDate,
string otherNumber, string orderNumber,
string shiftNumber,
bool includeDeletedThings)
{
using (DataContext context = new DataContext())
{
//your original code here
}
}
using
将正确处理上下文,并通过使用新的DbContext确保一个新的对象。保持DbContext存活有一些问题:
看到:
Life time of DbContext in a long-running process
Should the DbContext in EF have a short life span?
https://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext%28v=vs.103%29.aspx
Why re-initiate the DbContext when using the Entity Framework?
以上是关于避免实体框架查询返回的列表中的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章
如何使用模块化代码片段中的LeakCanary检测内存泄漏?