system.outofmemoryexception При заполнении DataAdapter? - PullRequest
4 голосов
/ 23 февраля 2011

Мне нужно вытащить 150K записей из БД. Я использую da.Fill(ds,"Query") и его бросок system.outofmemoryexception.

Dim daGrid As New SqlDataAdapter(sqlcmd_q)
daGrid.Fill(dsGrid, "Query")
daGrid.Dispose()

Мне нужен только этот набор данных. Я не могу использовать XML. потому что мне нужно назначить это MSChartControl для отображения ScotterPlot.

Есть предложения?

Ответы [ 3 ]

7 голосов
/ 23 февраля 2011

Первым делом я проверю, сколько столбцов вы возвращаете, и каковы их типы данных.Несмотря на то, что 150К записей много, это не должно давать вам исключения OOM, если длина каждой записи не превышает 13 КБ (на 32-разрядной машине).Это говорит о том, что вы либо возвращаете больше полей, чем вам нужно, или, возможно, некоторые из полей представляют собой очень большие строки или двоичные данные.Попробуйте сократить оператор select, чтобы получить только те поля, которые абсолютно необходимы для отображения.

Если это не сработает, вам может потребоваться перейти от DataTable к списку пользовательских типов данных (aкласс с соответствующими полями).

4 голосов
/ 23 февраля 2011

Вы не указали запрос.Убедитесь, что он содержит только нужные вам столбцы.

Если у вас все еще есть проблемы, попробуйте переключиться на 64-разрядную версию (если ваше оборудование поддерживает это, и у вас более 2 ГБ свободной памяти).

Если это не поможет, вам придется уменьшить объем памяти.Возможным вариантом будет визуализация графика без сохранения всех базовых данных в памяти.Просто загрузите данные одну за другой, вычислите координаты и сохраните их без сохранения основной записи.Может быть, вы даже можете позволить запросу сделать это.

1 голос
/ 31 января 2019

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

Во-первых, это DataTable, который являетсяпроблема не в DataAdapter.

Проблема может заключаться в том, что у вас действительно недостаточно памяти (в этом случае мой ответ не поможет).Вы можете сделать математику, чтобы выяснить, может ли это быть так - количество записей x приблизительное число байтов на запись.Если это приближается к 2 ГБ на 32-битной платформе или вашей доступной оперативной памяти на 64-битной платформе, тогда единственный вариант - уменьшить количество записей, количество полей или придумать подход, который использует DataReader вместо DataTable.

В вашем случае у вас есть 150 КБ записей, давайте предположим, что для каждой из них требуется 1 КБ памяти, что дает нам округлую цифру 150 МБ.Даже на 32-битной машине с 2 ГБ оперативной памяти это должно быть хорошо (при условии, что не происходит много подобного выделения памяти).В вашем случае у вас есть 64-битная машина с 128 ГБ ОЗУ (приятно).Логично, что вы не должны получать ошибки памяти.

Так в чем же причина проблемы?Это Куча Больших Объектов (LOH).Зачем?DataTable создает массив для хранения этих записей.Насколько я понимаю, он создает массив из 50, а затем увеличивается по мере добавления записей.Любое выделение памяти более 85 000 байт будет происходить из кучи больших объектов.(Вы работали на 64-битной платформе, так что получается, что как только вы достигнете 10 625 записей, выделения начнут поступать из кучи больших объектов.) Проблема с кучей больших объектов заключается в том, что она не уплотняется.Так что может быть много свободного места, но нет ни одного непрерывного блока, который достаточно велик.С .net 4.5 Microsoft улучшила его с точки зрения объединения смежных фрагментов, но не реорганизует их для создания больших блоков свободного пространства.В результате я получаю исключение «Недостаточно памяти». Как только вы заблуждаетесь в LOH, мой вопрос - только вопрос времени.

Решение?

установить начальную емкость DataTable.При извлечении записей из базы данных это будет означать сначала подсчет, так что это будет происходить за счет дополнительного запроса к базе данных, а затем:

.
.
dsGrid.InitialCapacity = count;
daGrid.Fill(dsGrid, "Query");
.
.

Хотя это не позволяет избежать отклонения от LOH, онодолжно означать, что он делает только одно распределение вместо нескольких.Таким образом, помимо исключения исключения из нехватки памяти, вы также должны получить выигрыш в производительности (компенсируемый необходимостью дополнительного запроса к базе данных).

Вы можете сделать сборщик мусора .net компактной кучей больших объектов, ноВы можете только сказать, чтобы сделать это в следующий раз, когда он работает.Я склонен использовать это, если я знаю, что заблудился в куче больших объектов.Это может быть излишним, но рассмотрите возможность внесения поправок в мое предложение:

.
.
dsGrid.InitialCapacity = count;
if (count > 10625)
{
    System.Runtime.GCSettings.LargeObjectHeapCompactionMode =
        System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce;
}
daGrid.Fill(dsGrid, "Query");
.
.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...