Delphi DataSnap 函数返回 TStream 和内存泄漏

Delphi DataSnap function returning TStream and memory leak

我使用的是基本的 DataSnap 服务器。 我正在使用 XE8,windows 8.1

我有下一个服务器功能:

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 Server 会注意释放它,否则我会遇到内存泄漏问题吗?

我做了一个实验来研究这个,结果让我很惊讶。

让 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;

,编译,在TMyStringStream.Destroy和运行.

中的Clear上打断点

然后,create/run 一个执行类似操作的最小客户端

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.

所以它看起来像是在您的服务器方法中分配的 Stream 并且分配给 它的结果将被释放(无论你喜欢与否),这样就不会泄漏。但我认为你应该将其视为一般规则的一个狭隘例外,即如果你通过局部变量创建一个 Delphi 对象,你应该在变量超出范围之前处理它。