Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 避免实体框架查询返回的列表中的内存泄漏_C#_.net_Entity Framework_Memory Leaks - Fatal编程技术网

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

C# 避免实体框架查询返回的列表中的内存泄漏,c#,.net,entity-framework,memory-leaks,C#,.net,Entity Framework,Memory Leaks,我想知道如何确保分配给对象列表的内存被释放 我在c.NET程序中有一个方法,它返回一个根据许多条件过滤的对象列表。编写该方法是为了使此筛选无法在一个查询中全部执行,因此它会在优化筛选时不断重新创建列表 我坚信这个方法是对内存负责的,因为在多次调用这个方法之后,用户报告了一个内存不足异常的崩溃 代码如下所示: private List<Things> GetMatchingThings(DataContext context, string number,

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

我在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对象还包含一个非托管属性

我的问题是我怎样才能

找到一种方法来释放中间查询中分配给thingList和filteredList的内存


b重写原始Where查询,以便在不需要某些搜索条件的情况下一次性完成此操作。有没有一种方法可以像SQL中那样在查询中使用通配符,例如,其中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的活动性存在一些问题:

见:


任何以4个空格开头的行都将标记为代码。选择代码行并按CTRL+K向所有这些行添加4个空格。是否重用DbContext。。。C使用垃圾收集器。如果某个值不再分配给任何变量或字段,则GC将收集该值。在上面的代码中,除了返回的列表之外的已分配列表将在下一个GC周期中被清除。在C中创建内存泄漏是相当困难的,一般来说,这意味着您在列表中存储了大量不打算存储的大型数据。请在@ikkentim的评论中添加一些内容:这段代码似乎没有内存泄漏。尽管传入DataContext上下文是可疑的,而且如果将所有结果存储在一个大怪物列表中,那么您就注定要失败。DbContext有一个更改跟踪程序。明智的做法是根据需要重新创建DbContextName,因此:不要在整个应用程序中使用相同的DbContextName。我没有看到.Where子句像以前那样重复。谢谢你,我也许可以用它一次完成更多的查询。这里的总体思路似乎是最好的方法。虽然我认为OP希望有条件地附加他的where查询。另一个问题:由于您将查询移动到EF,并非所有函数都可以像日期-时间比较那样进行转换。Stefan我很感激关于不让DbContext保持超过必要时间的建议,我知道这通常是推荐的。不幸的是,在这个应用程序的编写方式中,DbContext是一个被广泛重用的全局变量。该应用程序是WPF Windows窗体,全局DbContext用于填充该窗体,然后用于任何更新。事后看来,重新构造此应用程序将是一件好事,这样我们就不会像这样使用相同的DbContext,但不幸的是,这将需要进行广泛的重写,这在短期内是不可能的;然而,您可以尝试这样做,以便用当前代码隔离您的问题;如果有帮助的话,改变DbContext使用的冲动可能会增加。