I create a simple webservie, and I have a problem with application memory growth.
WebService:
// 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.
My Client
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;
Every time I execute btnClick action webservice growth 0.2MB (Out.pdf size). Ofcourse it return back desired file.
- GetI_Service is in autogenerated file from WSDL
- Ultimately, the website is to convert the uploaded file in TSoapAttachment and return it as TSoapAttachment.
CodePudding user response:
You are leaking outStream because you are passing it as reference to RetAttach
RetAttach.SetSourceStream(outStream, soReference);
You need to use soOwned instead as Ownership parameter. In that case memory management of outStream will be transferred to RetAttach instance and it will be automatically handled.
RetAttach.SetSourceStream(outStream, soOwned);
You are also needlessly wrapping try...finally with try...except that does nothing besides re-raising the exception.
try
try
...
finally
FreeAndNil(ReqAttach);
FreeAndNil(RespAttach);
end;
except
raise;
end;
You should just remove that useless try...except block, because following code has exactly the same effect.
try
...
finally
FreeAndNil(ReqAttach);
FreeAndNil(RespAttach);
end;
try...finally does not handle exception it merely runs code in finally block regardless of exception. After that code runs, exception will be automatically propagated to the next exception handler.
Additional issue in your code is that RespAttach is not initialized to nil and your call FreeAndNil(RespAttach) might be running on dangling pointer if the exception happens before it is assigned. Besides that FreeAndNil is also redundant here as you are dealing with local variables that are not going to be reused.
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;
