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 对象,你应该在变量超出范围之前处理它。
我使用的是基本的 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 对象,你应该在变量超出范围之前处理它。