2012-03-23 2 views
4

Я загружаю много данных в цикл, но после некоторых операций я их удаляю, но я вижу, что распределение памяти растет очень быстро, несколько секунд и 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

Нужен ли вызов ToList()? Вы можете уйти, не используя его, и, возможно, уменьшить распределение памяти таким образом. – KingCronus

+0

В этом отношении, зачем это сортировать, если вы просто хотите проверить, равен ли счет? вместо этого вы можете просто добавить 'Any()' после предложения where. Если нет элементов, он возвращает false, иначе true. Ему даже не нужно перебирать первый элемент в перечислимом (который проходит через место). – Servy

+0

нет, я удалил toList(), но это то же самое, мне нужно сделать sth на этих данных, поэтому мне нужно downlaod их всех не только infromation, сколько их из них. – kosnkov

ответ

12

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

Для 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.

Edit 2

... особенно ссылается на комментарий @James Reategui в ниже этой AsNoTracking уменьшает объем памяти:

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

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

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

  • Second: С другой стороны, когда сущности не привязаны к контексту, 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 порядка с исходными значениями = 3х10 = 30 байт запись
  • 1 снимок клиента с исходными значениями = 1x20 = 20 байт

Сумма: 100 байт

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

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

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

материализованные данные: (!)

  • 3 порядка объектов = 3x10 = 30 байт
  • 3 объектов клиента = 3x 20 = 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 может потребоваться больше памяти.

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

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

+0

EF> = 4.1 впервые услышал об этом, где я могу его получить? – kosnkov

+0

@kosnkov: EF 4.3.1 является текущей версией: http://blogs.msdn.com/b/adonet/archive/2012/02/29/ef4-3-1-and-ef5-beta-1-available- on-nuget.aspx Вы можете загрузить его в проект в VS2010 с помощью консоли менеджера пакетов Nuget: http://nuget.org/packages/EntityFramework/4.3.1 – Slauma

+0

@kosnkov: EF 4.0 и 'ObjectContext' также имеют возможность чтобы отключить отслеживание изменений, см. раздел «Редактирование». – Slauma

1

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

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

+0

ok в основном ур прав, а Slauma тоже немного прав, когда я создаю этот контекс в цикле, тогда momery перескакивает с 50 до 200 Мб, а затем снова спускается до 50, поэтому кажется, что сущность отслеживает все, что я делаю, не существует любой способ в EF 4.0 отключить его? если я хочу только загрузить данные? не меняйте их. – kosnkov