Предотвращение утечки памяти из списка, возвращаемого запросом структуры объекта - PullRequest
0 голосов
/ 03 сентября 2018

Я хотел бы знать, как я могу обеспечить освобождение памяти, выделенной для списка объектов.

У меня есть метод в программе на 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, не восстанавливается.

Насколько я знаю, вызов thingList.Clear () после создания каждого нового фильтрованного списка не поможет, поскольку Clear только удаляет элементы из списка, но не освобождает память.

Объект Thing также содержит свойство, которое неуправляемо.

У меня вопрос, как я могу

a) Найдите способ освободить память, выделенную для thingList и FilterList в промежуточных запросах

или

b) Перепишите оригинальный запрос Where, чтобы сделать все это за один раз, учитывая, что некоторые критерии поиска могут не понадобиться. Есть ли способ использовать подстановочный знак в запросе, как это, как в SQL, например .Where th.orderNumber.Equals ("%")

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

Пожалуйста, попробуйте следующее, чтобы исключить любые проблемы с 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 в живых:

См:

Время жизни DbContext в длительном процессе

Должен ли DbContext в EF иметь короткий срок службы?

https://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext%28v=vs.103%29.aspx

Зачем повторно запускать DbContext при использовании Entity Framework?

0 голосов
/ 03 сентября 2018

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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...