Есть ли решение проблемы потери памяти в FireDA C CopyDataSet и CopyRecord? - PullRequest
0 голосов
/ 03 апреля 2020

Я написал приложение, которое переносит серию таблиц Paradox в базу данных PostgreSQL. К сожалению, при импорте данных из таблицы Paradox в таблицу PostgreSQL увеличивается потребление памяти, а для одной из более крупных таблиц (1 миллион записей) происходит сбой импорта с исключением «недостаточно памяти». Этот cra sh возникает как при импорте данных с использованием CopyDataSet для таблицы в целом, так и при использовании CopyRecord для импорта данных по записи.

Я экспериментировал с узнать источник этой утечки памяти. Первоначально я думал, что источником является драйвер FireDA C ODB C. Или, точнее, я думал, что источником является драйвер Microsoft ODB C. Чтобы проверить это, я попытался импортировать из очень большой таблицы PostgreSQL в другую таблицу PostgreSQL, используя собственный драйвер FireDA C Postgres. Но утечка памяти сохранилась.

Я открываю исходную таблицу с помощью однонаправленного курсора (FetchOptions.Unidirectional: = True), который в состояниях документации будет отбрасывать записи, которые уже были обработаны при прямом сканировании, но утечка сохранилась. Во всех случаях я использовал FDQuery. Я пытался использовать FDTable с включенным режимом Live Data Windows (LDW), но существует несовместимость между драйвером Microsoft ODB C и FDTable, поэтому это было невозможно.

Здесь это базовый c код, который я использую для этого теста:

FDQuery1.SQL.Text := 'SELECT * FROM sourcetab;';
FDQuery1.FetchOptions.Unidirectional := True;
FDQuery1.FetchOptions.Mode := fmOnDemand;
FDQuery1.Open();
FDQuery2.SQL.Text := 'SELECT * FROM destinationtab WHERE False;';
FDQuery2.Open;
try
  while not FDQuery1.Eof do
  begin
    FDQuery2.Append;
    FDQuery2.CopyRecord( FDQuery1 );
    FDQuery2.Post;
    FDQuery1.Next;
  end;
finally
  FDQuery1.Close;
  FDQuery2.Close;
  ShowMessage( 'Done' );
end;

Я закончил тем, что закрыл и повторно открывал таблицу назначения каждые 1 000 добавлений. Закрытие таблицы назначения останавливает линейное увеличение использования памяти. Теперь, когда l oop выглядит следующим образом:

while not FDQuery1.Eof do
begin
  FDQuery2.Append;
  FDQuery2.CopyRecord( FDQuery1 );
  FDQuery2.Post;
  if (FDQuery1.RecNo mod  1000) = 0 then
  begin
    FDQuery2.Close;
    FDQuery2.Open;
  end;
  FDQuery1.Next;
end;

Я пробовал многие другие конфигурации FDQueries только для того, чтобы получить те же утечки.

Кто-нибудь еще заметил это поведение, и Кто-нибудь знает решение, которое имеет меньше накладных расходов, чем закрытие и повторное открытие целевого запроса?

Я наблюдаю за использованием памяти с помощью диспетчера задач. Как только использование памяти приближается к 2 ГБ, происходит сбой программы. Правильное закрытие набора данных назначения освобождает большой объем памяти.

ОС: Windows 10 64-разрядная, платформа: Delphi Rio 10.3.3, база данных: PostgreSQL 11, целевая платформа: 32- бит (без 64-битного драйвера Paradox ODB C)

1 Ответ

1 голос
/ 04 апреля 2020

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

Причиной увеличения памяти (утечки памяти нет!) Является количество добавляемых записей к внутренний буфер записи целевого запроса. Хотя Однонаправленный помогает ограничить память исходного запроса, он не может остановить целевой запрос на добавление записи после записи, увеличивая объем памяти с каждым. Поскольку к целевому запросу добавляются только записи, которые никогда не будут использованы или найдены, это полностью потрачено впустую.

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

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

Редактировать: На самом деле запрос может знать, что если можно освободить все предыдущие записи в буфере после Append и Post , когда Однонаправленный имеет значение True, но как FetchOption об этом нельзя думать во время Пост .

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