【问题标题】:Delphi DataSnap function returning TStream and memory leakDelphi DataSnap 函数返回 TStream 和内存泄漏
【发布时间】:2016-12-04 03:16:21
【问题描述】:

我正在使用基本的 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 服务器上的内存泄漏。

由于 result 是我创建的 TStream,Datasnap Server 会小心释放它,否则我会遇到内存泄漏问题?

【问题讨论】:

  • 服务器如何知道是否以及何时释放流?
  • @MartynA 这是一个具有调用生命周期的 DataSnap 服务器。你还问我想知道什么。
  • 对不起,我的 q 有点修辞。 如何服务器可能“知道”在例程中进行了哪些堆分配,更不用说撤消它们了?
  • 根据我的经验,这里不会出现内存泄漏。我在我的数据快照服务器中使用 Eurekalog,他们从未在我返回流的方法中检测到内存泄漏。
  • @nolaspeaker:你知道他们说什么,没有证据不是没有证据。在方法返回的流的析构函数上放置一个断点。它什么时候跳闸,是什么触发了它?

标签: delphi memory-leaks datasnap


【解决方案1】:

我做了一个实验来研究这个问题,结果让我感到惊讶。

让 DataSnapServer 向导(在 File | New | Other | Delphi Projects | 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上下断点,然后运行。

然后,创建/运行一个执行类似操作的最小客户端

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 中。

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

【讨论】:

  • 那么,这是否回答了你的问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多