Home > Net >  Memory leaks problem with using TsoapAttachment in SOAP WebService (Delphi)
Memory leaks problem with using TsoapAttachment in SOAP WebService (Delphi)

Time:12-30

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;
  • Related