2008-12-10 9 views
16

У меня динамический запрос, который возвращает около 590 000 записей. Он работает успешно в первый раз, но если я запустил его снова, я продолжаю получать System.OutOfMemoryException. Каковы некоторые причины, по которым это может произойти?Исключение типа 'System.OutOfMemoryException' было выбрано. Зачем?

Ошибка происходит здесь:

public static DataSet GetDataSet(string databaseName,string 
            storedProcedureName,params object[] parameters) 
    { 
     //Creates blank dataset 
     DataSet ds = null; 

     try 
     { 
      //Creates database 
      Database db = DatabaseFactory.CreateDatabase(databaseName); 
      //Creates command to execute 
      DbCommand dbCommand = db.GetStoredProcCommand(storedProcedureName); 
      dbCommand.CommandTimeout = COMMAND_TIMEOUT; 
      //Returns the list of SQL parameters associated with that stored proecdure 
      db.DiscoverParameters(dbCommand); 

      int i = 1; 
      //Loop through the list of parameters and set the values 
      foreach (object parameter in parameters) 
      { 
       dbCommand.Parameters[i++].Value = parameter; 
      } 
      //Retrieve dataset and set to ds 
      ds = db.ExecuteDataSet(dbCommand); 
     } 
      //Check for exceptions 
     catch (SqlException sqle) 
     { 
      throw sqle; 
     } 
     catch (Exception e) 
     { 
      throw e; // Error is thrown here. 
     } 
     //Returns dataset 
     return ds; 
    } 

Вот код пробеги по нажатию кнопки:

protected void btnSearchSBIDatabase_Click(object sender, EventArgs e) 
{ 

     LicenseSearch ls = new LicenseSearch(); 

     DataTable dtSearchResults = new DataTable(); 

     dtSearchResults = ls.Search(); 

     Session["dtSearchResults"] = dtSearchResults; 

     Response.Redirect("~/FCCSearch/SearchResults.aspx"); 
     } 
     else 
      lblResults.Visible = true; 
    } 
+0

Можем ли мы увидеть код? – 2008-12-10 16:30:23

+5

590K строк немного чрезмерно, не так ли? – StingyJack 2008-12-10 16:40:11

+0

Проблема не в том, что вы сохраняете DataTable в сеансе, а затем при повторном запросе у вас есть как переменные сеанса, так и исходный DataTable в памяти? BTW, не называйте `throw e;`, вызовите `throw;`, поскольку в противном случае ваша трассировка стека скажет, что обработчик `catch` сгенерировал исключение, когда на самом деле это содержащий код. – 2012-05-29 12:46:07

ответ

42

Он работает успешно в первый раз, но если я запускаю ее снова, я получаю System.OutOfMemoryException. Что такое - это некоторые причины, по которым это может быть происходит?

Независимо от того, что другие сказали, ошибка не имеет ничего общего с забывая распоряжаться вашей DbCommand или DBConnection, и вы не исправит свою ошибку, избавляясь от любого из них.

Ошибка имеет все, что связано с вашим набором данных, который содержит около 600 000 строк данных. По-видимому, ваш набор данных потребляет более 50% доступной памяти на вашем компьютере. Понятно, что у вас закончится память, когда вы вернете другой набор данных того же размера, прежде чем первый будет собран мусором. Просто как тот.

Вы можете решить эту проблему несколькими способами:

  • Рассмотрим возвращения меньше записей. Я лично не могу представить себе время, когда возвращение 600K записей когда-либо было полезным для пользователя. Чтобы свести к минимуму возвращаемые записи, попробуйте:

    • Ограничение вашего запроса до первых 1000 записей. Если из запроса возвращено более 1000 результатов, сообщите об этом пользователю, чтобы сузить результаты поиска.

    • Если ваши пользователи действительно настаивают на том, чтобы увидеть столько данных за один раз, попробуйте выполнить подкачку данных. Помните: Google никогда не показывает вам всего 22 бай-диона результатов поиска сразу, он показывает вам примерно 20 записей за раз. Google, вероятно, не сразу сохраняет все 22 бай-иллиона в памяти, вероятно, более эффективно использовать память для создания своей новой базы данных.

  • Если вам просто нужно перебирать данные и вам не нужен случайный доступ, попробуйте возвращающую DataReader вместо этого. Одновременно загружает только одну запись в память.

Если ни одна из них не является опцией, то вам необходимо принудительно.NET, чтобы освободить память, используемую в наборе данных перед вызовом метода с использованием одного из следующих методов:

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

  • Если вы не можете удалить все ссылки на ваш набор данных, очистите все строки из набора данных и любые объекты, привязанные к этим строкам. Это удаляет ссылки на datarows и позволяет их съедать сборщик мусора.

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

Примечание: вызов Dispose в вашем наборе данных не освобождает память и не вызывает сборщик мусора, а также не удаляет ссылку на ваш набор данных. Dispose используется для очистки неуправляемых ресурсов, но DataSet не имеет неуправляемых ресурсов. Он реализует только IDispoable, потому что он присущ MarshalByValueComponent, поэтому метод Dispose в наборе данных практически бесполезен.

7

Возможно, вы не утилизацией предыдущих классов соединения/результат от предыдущий запуск, что означает, что они все еще висят в памяти.

3

Вы, очевидно, не распоряжаетесь вещами.

Рассмотрите команду «использование», когда вы временно используете объекты, реализующие IDisposable.

0

Где это не удается?

Я согласен с тем, что ваша проблема, вероятно, в том, что ваш набор данных из 600 000 строк, вероятно, слишком велик. Я вижу, что вы добавляете его в сеанс. Если вы используете Sql-сеансовое состояние, ему также придется сериализовать эти данные.

Даже если вы правильно распоряжаетесь своими объектами, вы всегда будете иметь как минимум 2 копии этого набора данных в памяти, если вы запустите его дважды, один раз в сеансе, один раз в процедурный код. Это никогда не будет масштабироваться в веб-приложении.

Выполнение математики, 600 000 строк, даже с шагом 1-128 бит в строке, даст 9,6 мегабайт (600 тыс. * 128/8) только данных, не говоря уже о накладных данных набора данных.

Уточните результаты.

1

попытайтесь сломать ваши большие данные как можно больше, потому что я уже сталкивался с множеством раз таких проблем. В которой у меня выше 10 лакских записей с 15 колонками.

Смежные вопросы