2016-12-04 4 views
2

Я использую базовый сервер DataSnap. Я использую X Е8, окно 8.1Функция Delphi DataSnap, возвращающая TStream и утечку памяти

У меня есть следующая функция сервера:

function TSrvServerMetodos.ImagePac(pront:integer): TStream; 
var blob:TStream; 
    strm:TMemoryStream; 
begin 
    with qrytemp do begin 
     Params.Clear; 
     SQL.Clear; 
     SQL.Add('SELECT F.PICTURE FROM CLIENTES F WHERE F.PRONT=:pront'); 
     UnPrepare; 
     Prepare; 
     Params[0].Value:=pront; 
     Open; 
     if IsEmpty then result:=nil 
     else begin 
     try 
       Result := CreateBlobStream(fieldbyname('pict'),bmRead); 
       GetInvocationMetadata.ResponseContentType := 'image/jpeg'; 
     except 
       Result:=nil 
     end; 
     end; 
    end; 
end; 

Мой клиент приложение является Android приложения. Все работает хорошо, и я могу получить работу.

Мое сомнение касается утечки памяти на сервере Datasnap.

Поскольку результат - это TStream, который я создал, сервер Datasnap позаботится о его освобождении или у меня будут проблемы с утечкой памяти?

+1

Как сервер знал, будет ли и когда освобождать поток? – MartynA

+0

@MartynA Это сервер DataSnap с жизненным циклом вызова. Вы также спрашиваете, что я хочу знать. –

+0

Извините, мой q был немного риторическим. Как * может * сервер, возможно, «знает», какие распределения кучи были сделаны в рутине, не говоря уже об их уничтожении? – MartynA

ответ

4

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

Пусть Wizard DataSnapServer (в разделе Файл | Новый | Другое | Delphi Проекты | DataSnap Server) создать проект сервера по умолчанию, а затем сделать следующие дополнения

type 
    TMyStringStream = class(TStringStream) 
    public 
    constructor Create(Value : String); 
    destructor Destroy; override; 
    end; 

    TServerMethods1 = class(TDSServerModule) 
[...] 

function TServerMethods1.GetStream(Value: String): TStream; 
var 
    SS : TMyStringStream; 
begin 
    SS := TMyStringStream.Create(Value); 
    SS.Position := 0; 
    Result := SS; 
end; 

constructor TMyStringStream.Create(Value: String); 
begin 
    inherited Create; 
    WriteString(Value); 
end; 

destructor TMyStringStream.Destroy; 
begin 
    Clear; 
    inherited; 
end; 

, обобщать, поставить точку останова на Clear в TMyStringStream.Destroy и бежать.

Затем создайте/запустить минимальный клиент, который делает что-то вроде этого

procedure TDSClientForm.Button2Click(Sender: TObject); 
var 
    SS : TStringStream; 
    S : TStream; 
begin 
    SqlServerMethod2.Params[0].AsString := 'ABC123'; 
    SqlServerMethod2.ExecuteMethod; 
    SS := TStringStream.Create; 
    try 
    S := SqlServerMethod2.Params[1].AsStream; //, 6{SqlServerMethod2.Params[1].Size}); 
    S.Position := 0; 
    SS.CopyFrom(S, S.Size); 
    ShowMessage(SS.DataString); 
    finally 
    SS.Free; 
    end; 
end; 

Если вы выберите Button2 в клиенте, вы обнаружите, что сервер останавливается на точку останова в TMyStringStream.Destroy. Это является результатом FreeAndNil(FAllocatedReturn) выполнения в блоке

if not FServerSideCommand then 
    try 
     FreeAndNil(FAllocatedReturn) 
    except 
     Result := false 
    end; 

в function TDSMethodValues.ClearReferenceParameters: boolean в DataSnap.DSReflect.

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

+0

Итак, это ответ на ваш вопрос? – MartynA

+0

Да, спасибо. Ты сделал хорошую работу. –

Смежные вопросы