Должен ли я освободить объект Delphi, автоматически созданный из вызова веб-служб? - PullRequest
5 голосов
/ 29 марта 2010

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

В моей теме после того, как прошло X секунд (с использованием TTimer), я звоню:

procedure TPollingThread.OnTimer(Sender: TObject);
var
SystemProbeValues : TCWProbeValues;  
begin
SystemProbeValues := Remote.Run.GetSystemProbeValues;
PostMessage( ParentHandle, WM_APIEVENT ,Integer(apiMultiCellStatus), Integer(SystemProbeValues) );
end;

Функция Remote.Run.GetSystemProbeValues ​​имеет следующий прототип:

function GetSystemProbeValues : TCWProbeValues; stdcall;

И TCWProbeValues ​​- это динамический массив объектов TCWProbeValue (которые все происходят от TRemotable).

В моей основной форме я просто получаю сообщение и возвращаю LParam обратно в TCWProbeValues:

procedure TFrmCWMain.OnAPIEvent(var msg: TMessage);
begin
ProbeValues := TCWProbeValues(msg.LParam);
end;

Мой вопрос: учитывая, что динамический массив и его объекты были созданы системой Delphi HTTORIO, кто отвечает за их освобождение? Считал ли Delphi, что память можно использовать повторно после того, как вернулась моя функция OnTimer? (И в этом случае, мне просто повезло, что мой обработчик сообщений основной формы может фактически прочитать память, на которую ссылается LParam сообщения?) Или, скорее, я обязан освободить объект, автоматически созданный запросом HTTPRIO? 1014 *

Большое спасибо, пожалуйста, кричите, если выше нужно больше деталей / кода, и я добавлю к нему!

Приветствия, Дункан

1 Ответ

4 голосов
/ 29 марта 2010

TRemotable обеспечивает управление временем жизни через свойство DataContext, поэтому среда выполнения SOAP освобождает сам объект. Пока объект контекста данных существует, все, что он выделил, также будет существовать. Если вы хотите претендовать на владение и ответственность за объект, просто очистите его свойство DataContext. (Это, вероятно, то, что вы захотите сделать в этом случае, потому что ваше сообщение API-события может быть обработано после того, как событие SOAP завершено.)


Проблема в вашем коде в том, что вы передаете динамический массив через опубликованное сообщение. Когда ваша OnTimer процедура вернется к своему вызывающему, динамический массив, на который ссылается SystemProbeValues, уменьшит количество ссылок. Если другой поток еще не обработал сообщение (и, вероятно, не обработал), динамический массив может быть уже уничтожен к тому времени, когда он сможет обработать это сообщение.

Самый простой способ - очистить ссылку в обработчике событий таймера, не уменьшая счетчика ссылок, а затем сделать обратное в обработчике сообщений. После публикации сообщения очистите переменную:

LParam(SystemProbeValues) := 0;

В обработчике сообщений очистите старое значение глобальной переменной ProbeValues и присвойте новое значение следующим образом:

ProbeValues := nil;
LParam(ProbeValues) := Msg.LParam;

Другая проблема, скрывающаяся в вашем коде, может заключаться в использовании TTimer в потоке, отличном от VCL. Этот класс создает дескриптор окна для совместного использования всеми экземплярами класса. Если ваш поток таймера не является единственным потоком в программе, который использует TTimer, у вас, вероятно, будут проблемы, либо с функциями, выполняющимися в неправильном потоке, либо с функциями, которые вообще не работают. Вместо TTimer вы можете использовать SetTimer для создания таймера ОС вручную или вы можете создать ожидаемый таймер , который может быть более подходящим для использования в потоке, который не нужно реагировать на действия пользователя.

...