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;