Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Delphi Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2 3   вперед  Ctrl      все
 Утечка памяти при работе с DataSet  [new]
шК0ДЕР
Member

Откуда: Сызрань, городок на Волге
Сообщений: 71
Добрый день. К дб гриду (TDBGridEh - компонент EhLib 8.0 build 8.0.023) прикручен датасет. FetchAll := False естественно, т.к записей возвращается много, до 100к. Имеется функционал по выводу данных из грида в эксель(самописный). Для этого нужно знать общее кол-во записей в датасете, которое узнаю с помощью следующей процедуры
procedure GetDataSetRows;
var
  bm: TBookmark;
begin
  with FDataSet do
  begin
    DisableControls;
    bm := GetBookmark;
    First;
    FDataSetRows := 0;
    While not Eof do
    begin
      Inc(FDataSetRows);
      Next;
    end;
    GotoBookmark(bm);
    FreeBookmark(bm);
    EnableControls;
  end;
end;

Проблема возникает в цикле,
While not Eof do
    begin
      Inc(FDataSetRows);
      Next;
    end;
приложение съедает память до 1 гб (когда FDataSetRows инкрементируется до ~40к) и завершает работу с ошибкой "Out of memory". Если записей в датасете немного, то все работает без ошибок.

Подскажите, как можно исправить утечку или посчитать кол-во записей в датасете?
Вариант с возвращением кол-ва записей в запросе с сервера не лучший, т.к процедура по печати отчетов универсальная, а запросов для этих самых отчетов больше тысячи, накладно все их дописывать
20 ноя 17, 10:36    [20968149]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 2468
шК0ДЕР,

Это не утечка, а просто не хватает памяти для такого огромного буффера.
20 ноя 17, 10:42    [20968175]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 2468
шК0ДЕР,

Выход один:
1. Для получения каунта использовать отдельно select count(*) from;
2. В отчет выводить постранично (скажем, по 1000 записей). (что-то типа select first 1000 step 5000)
20 ноя 17, 10:45    [20968197]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
шК0ДЕР
Member

Откуда: Сызрань, городок на Волге
Сообщений: 71
Этого то я и боялся...
20 ноя 17, 10:46    [20968205]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 2468
Хотя подожди... При
шК0ДЕР
FetchAll := False

Такого может и не должно быть. Может действительно утечка в компонентах доступа или еще где?
20 ноя 17, 10:48    [20968217]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
шК0ДЕР
Member

Откуда: Сызрань, городок на Волге
Сообщений: 71
Тоже странным показалось, компоненты проверил, вроде чисто. Смотрел при отладке в диспетчере задач, память утекает именно при переборе записей датасета. В Locate() кстати та же проблема.
Пытался решить вот чем:
DBGrid.DataSource.DataSet := nil;
While not Eof do
begin
   Inc(FDataSetRows);
   Next;
end;
DBGrid.DataSource.DataSet := FDataSet;

DBGrid.DataSource.Enabled := False;
While not Eof do
begin
   Inc(FDataSetRows);
   Next;
end;
DBGrid.DataSource.Enabled := True;

заменяя цикл на
Last;
FDataSetRows := RecNo;

Для эксперемента прописал Refresh в цикле, память, потребляемая приложением сбрасывается до обычной - 8к.
20 ноя 17, 10:57    [20968264]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 2468
шК0ДЕР
заменяя цикл на
Last;
FDataSetRows := RecNo;
Если в твоих компонентах работает RecNo после Last, зачем проктология с циклом тогда.
20 ноя 17, 10:59    [20968276]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
шК0ДЕР
Member

Откуда: Сызрань, городок на Волге
Сообщений: 71
YuRock, код не мой. В любом случае при выполнении метода Last(который так и не выполняется до конца) происходит та же котовасия с памятью. Компонент TOracleDataSet, DOA
20 ноя 17, 11:06    [20968330]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 2468
шК0ДЕР,

Может это компонент и не умеет при отключенном FetchAll буффер определенного размера только помнить.
А с другой стороны, вряд ли такое возможно. Ведь всегда должны быть возможны Prev или First. А как такое сделать на уровне базы? Наверно никак. Unfetch какой-нибудь если и есть где-то, то не везде и не всегда может сработать.
Т.ч. Только переделывать.
20 ноя 17, 11:14    [20968381]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
шК0ДЕР
Member

Откуда: Сызрань, городок на Волге
Сообщений: 71
YuRock, разобрался как кол-во строк подсчитывалось. В компоненте было отключено свойство CountAllRecords и ReсordCount возвращал кол-во видимых записей из грида. При включенному свойстве возвращается общее кол-во записей.
Но проблема осталась. При самой печати данных происходит перебор записей датасета. Отчет недоформировывается
20 ноя 17, 11:28    [20968478]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
makhaon
Member

Откуда: A galaxy far far away
Сообщений: 2091
Это нормальное, обычное поведение. Наборы данных обычно держат все данные в памяти. Вот представьте - что всю выборку из базы всунули в память + обвязка (т.к данные в памяти не в raw же хранить).

автор
Ведь всегда должны быть возможны Prev или First.


Проблема даже не в Prev/First, как раз таки Prev/First сделать не проблема. Проблема в том, что вся выборка может понадобится для отображения в гриде и как тогда по-другому сделать? Кроме как тащить весь набор в память.

While not Eof do
    begin
      Inc(FDataSetRows);
      Next;
    end;


Это тоже самое, что FetchAll, это FetchAll и есть.

автор
Подскажите, как можно исправить утечку или посчитать кол-во записей в датасете?


1. Это не утечка памяти. Это обычная, нормальная работа. Наборы именно так и работают.
2. Если не нужно отображать данные в гриде, то можно взять набор, который не тащит все данные в память, а выбирает только текущую запись. В случае IBX, например, это TIBSQL. В других наборах компонент может быть по-разному: от отдельной компоненты до опций в пределах одной.
3. Намного лучше вместо того, что бы считать количество записей на клиенте посчитать их сервером, отдав ему соответствующий запрос (select count(some_field) as counter from database).
20 ноя 17, 11:32    [20968501]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
makhaon
Member

Откуда: A galaxy far far away
Сообщений: 2091
4. Если же нужно отображать набор в гриде - то либо ограничивать количество записей в наборе, либо переходить на 64х.
20 ноя 17, 11:35    [20968520]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
шК0ДЕР
Member

Откуда: Сызрань, городок на Волге
Сообщений: 71
makhaon, с кол-вом записей уже разобрался. Проблема теперь при печати отчета. Хотя способ аналогичен...
While not DataSet.Eof do
begin
   //печать данных
   Next;
end;
Есть еще какие-либо идеи кроме печати данных по частям?
20 ноя 17, 11:40    [20968551]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
makhaon
Member

Откуда: A galaxy far far away
Сообщений: 2091
шК0ДЕР,

автор
переходить на 64х
20 ноя 17, 11:53    [20968599]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
makhaon
Member

Откуда: A galaxy far far away
Сообщений: 2091
сделать отдельный набор именно для печати, как я говорил:
"можно взять набор, который не тащит все данные в память, а выбирает только текущую запись. В случае IBX, например, это TIBSQL"
20 ноя 17, 11:56    [20968608]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
schi
Member

Откуда: Москва
Сообщений: 2353
шК0ДЕР
makhaon, с кол-вом записей уже разобрался. Проблема теперь при печати отчета. Хотя способ аналогичен...
While not DataSet.Eof do
begin
   //печать данных
   Next;
end;
Есть еще какие-либо идеи кроме печати данных по частям?


Использовать unidirectional dataset, например
20 ноя 17, 12:20    [20968687]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
LSV
Member

Откуда: Киев
Сообщений: 30148
Вообще-то чтобы зачитать весь ДС (кот. зачитан не целиком), достаточно стать в его конец (last), в потом вернуться.
Тогда станет известно кол-во записей. И можно начинать экспорт.
20 ноя 17, 13:01    [20968863]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
schi
Member

Откуда: Москва
Сообщений: 2353
LSV
Вообще-то чтобы зачитать весь ДС (кот. зачитан не целиком), достаточно стать в его конец (last), в потом вернуться.
Тогда станет известно кол-во записей. И можно начинать экспорт.


Попробуй на больших объемах, тебе понравится.
20 ноя 17, 13:04    [20968872]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
_Vasilisk_
Member

Откуда: Украина, Харьков
Сообщений: 9916
schi
Использовать unidirectional dataset, например
Или вообще не датасет. Что-то типа TIBSQL
20 ноя 17, 13:31    [20969005]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
DimaBr
Member

Откуда:
Сообщений: 10271
Будь я твоим руководителем, я бы заставил тебя пролистать все 100к строк
20 ноя 17, 13:46    [20969055]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
LSV
Member

Откуда: Киев
Сообщений: 30148
schi
LSV
Вообще-то чтобы зачитать весь ДС (кот. зачитан не целиком), достаточно стать в его конец (last), в потом вернуться.
Тогда станет известно кол-во записей. И можно начинать экспорт.


Попробуй на больших объемах, тебе понравится.
А то я не пробовал... :)
Все равно это придется грузить, чтобы экспортировать. Объем вычислений будет одинаковым.
20 ноя 17, 14:44    [20969272]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
DarkMaster
Member

Откуда: Donetsk,Ukraine
Сообщений: 5628
YuRock

Может это компонент и не умеет при отключенном FetchAll буффер определенного размера только помнить.
А с другой стороны, вряд ли такое возможно. Ведь всегда должны быть возможны Prev или First. А как такое сделать на уровне базы? Наверно никак. Unfetch какой-нибудь если и есть где-то, то не везде и не всегда может сработать.
Т.ч. Только переделывать.


Без привязки к конкретному вопросу вставлю свои 5 копеек - есть такая штука как TIB_Cursor (библиотека IBObjects) - там буфер выделяется ровно на одну запись из БД и сам TIB_Cursor умеет только Next(). Самое то для ТС, если найдутся аналоги.
20 ноя 17, 14:52    [20969313]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
JaDi
Member

Откуда: Сызрань, Россия
Сообщений: 3196
Там в этой базе файлы в блобах хранятся что ли? Как-то многова-то веса (аж гигабайт) для всего 40к строчек.
20 ноя 17, 15:02    [20969349]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 2468
JaDi
Там в этой базе файлы в блобах хранятся что ли? Как-то многова-то веса (аж гигабайт) для всего 40к строчек.
Блобы как раз не тянутся. Может, строки длинные
20 ноя 17, 16:00    [20969610]     Ответить | Цитировать Сообщить модератору
 Re: Утечка памяти при работе с DataSet  [new]
YuRock
Member

Откуда: Донецк
Сообщений: 2468
А может и SELECT* убрать можно и поможет.
20 ноя 17, 16:01    [20969615]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2 3   вперед  Ctrl      все
Все форумы / Delphi Ответить