在 SOAP WebService 中使用 TsoapAttachment 的内存泄漏问题 (Delphi)
Memory leaks problem with using TsoapAttachment in SOAP WebService (Delphi)
我创建了一个简单的 webservie,但我遇到了应用程序内存增长的问题。
网络服务:
// Impl File
type
{ T_Service }
T_Service = class(TInvokableClass, I_Service)
public
function Convert(ReqAttach: TSOAPAttachment): TSOAPAttachment; stdcall;
end;
implementation
function T_Service.Convert(
ReqAttach: TSOAPAttachment): TSOAPAttachment;
var
memStream : TMemoryStream;
outStream : TMemoryStream;
try
ReqAttach.SaveToStream(memStream);
outStream.LoadFromFile('D:\Out.pdf');
RetAttach.SetSourceStream(outStream, soReference);
finally
memStream.Free;
end;
end;
initialization
{ Invokable classes must be registered }
InvRegistry.RegisterInvokableClass(T_Service);
end.
//Intf file
type
I_Service = interface(IInvokable)
['{69440128-AC9D-43CC-9A11-7B6B36F15D1E}']
function Convert(ReqAttach: TSOAPAttachment): TSOAPAttachment; stdcall;
end;
implementation
initialization
{ Invokable interfaces must be registered }
InvRegistry.RegisterInterface(TypeInfo(I_Service));
end.
我的客户
procedure TClientForm.btnClick(Sender: TObject);
var
ReqAttach: TSOAPAttachment;
RespAttach: TSOAPAttachment;
Service: I_Service;
begin
ReqAttach := TSOAPAttachment.Create;
Service := unitIMyService.GetI_Service();
try
try
ReqAttach.SetSourceFile('D:\In.pdf');
RespAttach := Service.Convert(ReqAttach);
RespAttach.SaveToFile('D:\Resp.pdf');
finally
FreeAndNil(ReqAttach);
FreeAndNil(RespAttach);
end;
except
raise;
end;
end;
每次执行 btnClick 动作时,web 服务增长 0.2MB(Out.pdf 大小)。当然,它 return 返回所需的文件。
- GetI_Service 位于 WSDL 自动生成的文件中
- 最终网站是将TSoapAttachment中上传的文件进行转换return为TSoapAttachment
您正在泄漏 outStream
因为您将其作为参考传递给 RetAttach
RetAttach.SetSourceStream(outStream, soReference);
您需要使用 soOwned
作为 Ownership
参数。在这种情况下,outStream
的内存管理将转移到 RetAttach
实例,并将自动处理。
RetAttach.SetSourceStream(outStream, soOwned);
您还不必要地用 try...except
包装了 try...finally
,除了重新引发异常之外什么都不做。
try
try
...
finally
FreeAndNil(ReqAttach);
FreeAndNil(RespAttach);
end;
except
raise;
end;
你应该删除那个无用的 try...except
块,因为下面的代码具有完全相同的效果。
try
...
finally
FreeAndNil(ReqAttach);
FreeAndNil(RespAttach);
end;
try...finally
不处理异常它只是在 finally
块中运行代码而不考虑异常。该代码运行后,异常将自动传播到下一个异常处理程序。
代码中的其他问题是 RespAttach
未初始化为 nil,如果异常发生在分配之前,您的调用 FreeAndNil(RespAttach)
可能是悬空指针上的 运行。除此之外 FreeAndNil
在这里也是多余的,因为您正在处理不会被重用的局部变量。
procedure TClientForm.btnClick(Sender: TObject);
var
ReqAttach: TSOAPAttachment;
RespAttach: TSOAPAttachment;
Service: I_Service;
begin
RespAttach := nil;
ReqAttach := TSOAPAttachment.Create;
try
Service := unitIMyService.GetI_Service();
ReqAttach.SetSourceFile('D:\In.pdf');
RespAttach := Service.Convert(ReqAttach);
RespAttach.SaveToFile('D:\Resp.pdf');
finally
ReqAttach.Free;
RespAttach.Free;
end;
end;
我创建了一个简单的 webservie,但我遇到了应用程序内存增长的问题。
网络服务:
// Impl File
type
{ T_Service }
T_Service = class(TInvokableClass, I_Service)
public
function Convert(ReqAttach: TSOAPAttachment): TSOAPAttachment; stdcall;
end;
implementation
function T_Service.Convert(
ReqAttach: TSOAPAttachment): TSOAPAttachment;
var
memStream : TMemoryStream;
outStream : TMemoryStream;
try
ReqAttach.SaveToStream(memStream);
outStream.LoadFromFile('D:\Out.pdf');
RetAttach.SetSourceStream(outStream, soReference);
finally
memStream.Free;
end;
end;
initialization
{ Invokable classes must be registered }
InvRegistry.RegisterInvokableClass(T_Service);
end.
//Intf file
type
I_Service = interface(IInvokable)
['{69440128-AC9D-43CC-9A11-7B6B36F15D1E}']
function Convert(ReqAttach: TSOAPAttachment): TSOAPAttachment; stdcall;
end;
implementation
initialization
{ Invokable interfaces must be registered }
InvRegistry.RegisterInterface(TypeInfo(I_Service));
end.
我的客户
procedure TClientForm.btnClick(Sender: TObject);
var
ReqAttach: TSOAPAttachment;
RespAttach: TSOAPAttachment;
Service: I_Service;
begin
ReqAttach := TSOAPAttachment.Create;
Service := unitIMyService.GetI_Service();
try
try
ReqAttach.SetSourceFile('D:\In.pdf');
RespAttach := Service.Convert(ReqAttach);
RespAttach.SaveToFile('D:\Resp.pdf');
finally
FreeAndNil(ReqAttach);
FreeAndNil(RespAttach);
end;
except
raise;
end;
end;
每次执行 btnClick 动作时,web 服务增长 0.2MB(Out.pdf 大小)。当然,它 return 返回所需的文件。
- GetI_Service 位于 WSDL 自动生成的文件中
- 最终网站是将TSoapAttachment中上传的文件进行转换return为TSoapAttachment
您正在泄漏 outStream
因为您将其作为参考传递给 RetAttach
RetAttach.SetSourceStream(outStream, soReference);
您需要使用 soOwned
作为 Ownership
参数。在这种情况下,outStream
的内存管理将转移到 RetAttach
实例,并将自动处理。
RetAttach.SetSourceStream(outStream, soOwned);
您还不必要地用 try...except
包装了 try...finally
,除了重新引发异常之外什么都不做。
try
try
...
finally
FreeAndNil(ReqAttach);
FreeAndNil(RespAttach);
end;
except
raise;
end;
你应该删除那个无用的 try...except
块,因为下面的代码具有完全相同的效果。
try
...
finally
FreeAndNil(ReqAttach);
FreeAndNil(RespAttach);
end;
try...finally
不处理异常它只是在 finally
块中运行代码而不考虑异常。该代码运行后,异常将自动传播到下一个异常处理程序。
代码中的其他问题是 RespAttach
未初始化为 nil,如果异常发生在分配之前,您的调用 FreeAndNil(RespAttach)
可能是悬空指针上的 运行。除此之外 FreeAndNil
在这里也是多余的,因为您正在处理不会被重用的局部变量。
procedure TClientForm.btnClick(Sender: TObject);
var
ReqAttach: TSOAPAttachment;
RespAttach: TSOAPAttachment;
Service: I_Service;
begin
RespAttach := nil;
ReqAttach := TSOAPAttachment.Create;
try
Service := unitIMyService.GetI_Service();
ReqAttach.SetSourceFile('D:\In.pdf');
RespAttach := Service.Convert(ReqAttach);
RespAttach.SaveToFile('D:\Resp.pdf');
finally
ReqAttach.Free;
RespAttach.Free;
end;
end;