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

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

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

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

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

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
20
0
12 564
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

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

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

using(DataContext myDC = new DataContext)
{
  //  Do stuff
} //DataContext is disposed
Ответ принят как подходящий

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

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

Sam Schutte 24.09.2008 18:43

Да, использовать или немного datacontext зависит от вашего количества данных, вы можете узнать, как с этим справиться, я узнал из серии RobConery MVC Road ... blog.wekeroad.com/category/mvc-storefront

Jonathan Escobedo 04.09.2009 19:01

Вот как можно вызвать ClearCache (): context.GetType (). InvokeMember («ClearCache», BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, context, null);

Rafe 08.11.2010 19:42

+1, хотя я обнаружил, что мне нужен еще один флаг привязки, чтобы сообщить ему о вызове метода: BindingFlags.InvokeMethod.

Jason 12.11.2010 00:38

Я пробовал «DataContext.ObjectTrackingEnabled в false», но когда я запускаю профилировщик памяти, он указывает, что это удалено, но не может быть GCed.

visual 23.01.2013 13:58

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

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

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

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

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
   }
}

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

Другие вопросы по теме