Запрос данных объекта и утечка памяти - PullRequest
4 голосов
/ 23 марта 2012

Я загружаю много данных в цикле, но после некоторых операций я удаляю их, но я вижу, что выделение памяти растет очень быстро, несколько секунд и 1 ГБ, так как можно очищать после каждой итерации?

    using (var contex = new DB)
    {

        var inputs = contex.AIMRInputs.Where(x => x.Input_Type == 1);

        foreach (var input in inputs)
        {
            var data = contex.Values.Where(x => x.InputID == input.InputID).OrderBy(x => x.TimeStamp).ToList();

            if (data.Count == 0) continue;
            foreach (var value in data)
            {
               Console.WriteLine(Value.property);
            }
            data.Clear();


        }
    }

Ответы [ 2 ]

12 голосов
/ 23 марта 2012

Первое, что вы можете сделать, это отключить отслеживание изменений, потому что вы не меняете данные в своем коде. Это предотвращает привязку загруженных объектов к контексту:

Для DbContext (EF> = 4.1):

var inputs = contex.AIMRInputs.AsNoTracking()
    .Where(x => x.Input_Type == 1);

И

var data = contex.Values.AsNoTracking()
    .Where(x => x.InputID == input.InputID)
    .OrderBy(x => x.TimeStamp)
    .ToList();

Редактировать

Для EF 4.0 вы можете оставить свои запросы такими, какие они есть, но добавить следующие две первые строки в блоке using:

contex.AIMRInputs.MergeOption = MergeOption.NoTracking;
contex.Values.MergeOption = MergeOption.NoTracking;

Это отключает отслеживание изменений для ObjectContext.

Редактировать 2

... особенно в связи с комментарием @James Reategui ниже, что AsNoTracking уменьшает объем памяти:

Это часто верно (как в модели / запросе этого вопроса), но не всегда! На самом деле использование AsNoTracking может быть контрпродуктивным в отношении использования памяти.

Что делает AsNoTracking, когда объекты материализуются в памяти?

  • Во-первых: он не присоединяет сущность к контексту и, следовательно, не создает записи в менеджере состояний контекста. Эти записи занимают память. При использовании POCO записи содержат снимок значений свойств объекта, когда он был впервые загружен / присоединен к контексту - в основном копия всех (скалярных) свойств в дополнение к самому объекту. Таким образом, потребляемая память занимает (примерно) вдвое больше размера объекта, когда AsNoTracking не применяется.

  • Второе: с другой стороны, когда сущности не привязываются к контексту, EF не может использовать преимущество сопоставления идентификаторов между значениями ключей и ссылочными идентификаторами объектов. Это означает, что объекты с одним и тем же ключом будут материализованы несколько раз, что потребляет дополнительную память, а без использования AsNoTracking EF обеспечит материализацию объекта только один раз для значения ключа.

Второй момент становится особенно важным, когда загружаются связанные объекты. Простой пример:

Скажем, у нас есть сущность Order и Customer, и у заказа есть один клиент Order.Customer. Скажем, объект Order имеет размер 10 байт, а объект Customer - 20 байт. Теперь мы запускаем этот запрос:

var orderList = context.Orders
    .Include(o => o.Customer).Take(3).ToList();

И предположим, что для всех 3 загруженных заказов назначен один и тот же клиент. Поскольку мы не отключили отслеживание, EF материализуется:

  • 3 порядка объектов = 3x10 = 30 байт
  • 1 объект клиента = 1x20 = 20 байт (поскольку контекст признает, что клиент одинаков для всех 3 заказов, он материализует только один объект клиента)
  • 3 записи снимка порядка с исходными значениями = 3x10 = 30 байт
  • 1 запись снимка клиента с исходными значениями = 1x20 = 20 байт

Сумма: 100 байт

(Для простоты я предполагаю, что записи контекста со скопированными значениями свойств имеют тот же размер, что и сами сущности.)

Теперь мы запускаем запрос с отключенным отслеживанием изменений:

var orderList = context.Orders.AsNoTracking()
    .Include(o => o.Customer).Take(3).ToList();

Материализованные данные:

  • 3 заказа объектов = 3x10 = 30 байт
  • 3 (!) Объекта клиента = 3x20 = 60 байт (без сопоставления идентификаторов = несколько объектов на ключ, все три объекта клиента будут иметь одинаковые значения свойств, но они по-прежнему три объекта в памяти)
  • Нет записей моментальных снимков

Сумма: 90 байт

Таким образом, при использовании AsNoTracking запрос потребляет на 10 байт меньше памяти.

Теперь тот же расчет с 5 заказами (Take(5)), снова все заказы имеют одного и того же клиента:

Без AsNoTracking:

  • 5 заказов объектов = 5x10 = 50 байт
  • 1 объект клиента = 1x20 = 20 байт
  • 5 записей снимка порядка с исходными значениями = 5x10 = 50 байт
  • 1 запись снимка клиента с исходными значениями = 1x20 = 20 байт

Сумма: 140 байт

С AsNoTracking:

  • 5 заказов объектов = 5x10 = 50 байт
  • 5 (!) Объектов клиента = 5x20 = 100 байт
  • Нет записей моментальных снимков

Сумма: 150 байт

На этот раз использование AsNoTracking было на 10 байт дороже.

Приведенные выше цифры очень грубые, но где-то точка безубыточности, где использование AsNoTracking может потребовать большеmemory.

Разница в потреблении памяти между использованием AsNoTracking или не сильно зависит от запроса, отношений в модели и конкретных данных, которые загружаются запросом.Например: AsNoTracking всегда будет лучше в потреблении памяти, когда заказы в приведенном выше примере (или в основном) имеют разных клиентов.

Вывод: AsNoTracking в первую очередь предназначен как инструмент для улучшения запроса производительность , а не использование памяти.Во многих случаях он также будет занимать меньше памяти.Но не удивляйтесь, если конкретному запросу требуется больше памяти с AsNoTracking.В конце концов, вы должны измерить объем памяти для принятия твердого решения в пользу или против AsNoTracking.

1 голос
/ 23 марта 2012

Часть, если проблема здесь может быть связана с DataContext. Многие из них кешируют информацию или хранят дополнительную информацию по мере выполнения запросов, и поэтому ее объем памяти со временем будет расти. Сначала я бы проверил с помощью профилировщика, но если это ваша проблема, вам может потребоваться заново создавать новый текстовый текст после каждого запроса X (поэкспериментируйте с различными значениями X, чтобы увидеть, что работает лучше).

Я также хотел бы отметить, что у большинства людей, как правило, много памяти. Вы должны быть действительно уверены, что используете больше памяти, чем на самом деле приемлемо, прежде чем приступать к оптимизации такого типа. GC также начнет более агрессивно очищать память, так как у вас меньше свободной памяти для работы. Это не мешает преждевременной оптимизации (и вам не следует).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...