Как избежать утечки памяти с помощью LINQ-To-SQL? - PullRequest
20 голосов
/ 23 сентября 2008

У меня были некоторые проблемы с LINQ-To-SQL, связанные с использованием памяти. Я использую его в службе Windows, чтобы выполнить некоторую обработку, и я перебираю большой объем данных, которые извлекаю из контекста. Да, я знаю, что мог бы сделать это с помощью хранимой процедуры, но есть причины, по которым это было бы не идеальным решением.

Во всяком случае, в основном я вижу, что память не освобождается даже после того, как я позвонил context.SubmitChanges(). Таким образом, я вынужден делать всевозможные странные вещи, например, извлекать 100 записей за раз или создавать несколько контекстов, чтобы они все выполняли отдельные задачи. Если я оставлю тот же DataContext и использую его позже для других вызовов, он просто съедает все больше и больше памяти. Даже если я вызову Clear() в массиве "var tableRows", который мне возвращает запрос, задаю для него значение null и вызову SYstem.GC.Collect() - он все равно не освобождает память.

Теперь я прочитал кое-что о том, как вы должны быстро использовать DataContexts и быстро их утилизировать, но кажется, что они должны быть способом заставить контекст сбросить все свои данные (или все свои данные отслеживания для определенной таблицы) в определенный момент, чтобы гарантировать, что память свободна.

Кто-нибудь знает, какие шаги гарантируют освобождение памяти?

Ответы [ 5 ]

20 голосов
/ 23 сентября 2008

DataContext отслеживает все объекты, которые он когда-либо выбирал. Он не выпустит это, пока не будет собран мусор. Кроме того, поскольку он реализует IDisposable, вы должны вызвать Dispose или использовать оператор using.

Это правильный путь:

using(DataContext myDC = new DataContext)
{
  //  Do stuff
} //DataContext is disposed
15 голосов
/ 23 сентября 2008

Если вам не нужно отслеживание объекта, установите DataContext.ObjectTrackingEnabled в false . Если вам это нужно, вы можете использовать рефлексию для вызова внутреннего DataContext.ClearCache () , хотя вы должны знать, что, поскольку он внутренний, он может исчезнуть в будущей версии платформы. И, насколько я могу судить, сама структура не использует его, но очищает кеш объекта.

6 голосов
/ 23 сентября 2008

Как указывает Дэвид, вы должны избавиться от DataContext, используя блок using.

Похоже, ваша основная задача - создать и утилизировать группу объектов DataContext. Это то, как linq2sql разработан. DataContext должен иметь короткий срок службы. Поскольку вы извлекаете много данных из БД, имеет смысл использовать много памяти. Вы на правильном пути, обрабатывая ваши данные кусками.

Не бойтесь создавать тонны DataContexts. Они предназначены для использования таким образом.

3 голосов
/ 24 сентября 2008

Спасибо, ребята - я проверю метод ClearCache. Просто для пояснения (для будущих читателей) ситуация, в которой я получал использование памяти, была примерно такой:

using(DataContext context = new DataContext())
{
   while(true)
   {
      int skipAmount = 0;
      var rows = context.tables.Select(x => x.Dept == "Dept").Skip(skipAmount).Take(100);

      //break out of loop when out of rows

      foreach(table t in rows)
      {
         //make changes to t   
      }

      context.SubmitChanges();
      skipAmount += rows.Count();

      rows.Clear();
      rows = null;

      //at this point, even though the rows have been cleared and changes have been
      //submitted, the context is still holding onto a reference somewhere to the
      //removed rows.  So unless you create a new context, memory usuage keeps on growing
   }
}
0 голосов
/ 16 сентября 2016

Я только что столкнулся с подобной проблемой. В моем случае помогло установить свойства DataContext.ObjectTrackingEnabled в false. Но это работает только в случае итерации строк следующим образом:

using (var db = new DataContext())
{
    db.ObjectTrackingEnabled = false;
    var documents = from d in db.GetTable<T>()
                     select d;
    foreach (var doc in documents)
    {
        ...
    }
}

Если, например, в запросе использовать методы ToArray () или ToList () - без эффекта

...