避免实体框架查询返回的列表中的内存泄漏

问题描述 投票:0回答:2

我想知道如何确保分配给对象列表的内存将被释放。

我在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# .net entity-framework memory-leaks
2个回答
1
投票

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();

0
投票

请尝试以下操作以排除任何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?

© www.soinside.com 2019 - 2024. All rights reserved.