Подтвердить что ты не робот

Как избежать утечки памяти с помощью LINQ-To-SQL?

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

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

using(DataContext myDC = new DataContext)
{
  //  Do stuff
} //DataContext is disposed

Ответ 3

Как указывает David Points, вы должны избавиться от DataContext с помощью используемого блока.

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

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

Ответ 4

Спасибо, ребята, я проверю метод 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
   }
}

Ответ 5

Я столкнулся с подобной проблемой. В моем случае, помогли установить свойства 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() - no effect