Возникло исключение типа System.OutOfMemoryException. Зачем? - PullRequest
17 голосов
/ 10 декабря 2008

У меня динамический запрос, который возвращает около 590 000 записей. Он запускается успешно в первый раз, но если я запустил его снова, я получаю 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;
    }

Ответы [ 5 ]

43 голосов
/ 10 декабря 2008

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

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

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

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

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

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

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

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

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

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

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

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

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

7 голосов
/ 10 декабря 2008

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

3 голосов
/ 10 декабря 2008

Вы явно не избавляетесь от вещей.

Учитывайте команду «using» при временном использовании объектов, реализующих IDisposable.

1 голос
/ 13 апреля 2012

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

0 голосов
/ 10 декабря 2008

Где это терпит неудачу?

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

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

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

Обрежьте свои результаты.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...