Memory leak in delphi DA server

It looks like our DA server is leaking memory for DA GetData calls.

It looks like each call to GetData creates some objects (TROMSXMLNode,TROMSXMLDocument, TableRequestInfoV5) which don’t get destroyed.

The server code is pretty basic (see below)

What’s responsible of freeing the memory?
What could be going wrong?

  TTPEService = class(TDataAbstractService, ITPEService)
...
function TTPEService.OffGetData(const aTableNameArray:StringArray;const aTableRequestInfoArray:TableRequestInfoArray;
   const MaxRecords:Integer;const StatementName,StatementSuffix,OrderClause:String;const PrfPrimkey:Integer;
   const SecurityContext,ExtraWhereClause:String):Binary;
var
  i:integer;
begin
  if SecurityService().CheckAddUserFilter(aTableNameArray,aTableRequestInfoArray,PrfPrimkey,SecurityContext) then
    Self.AllowWhereSQL:=True;
  if AppendUserFilter(aTableRequestInfoArray,ExtraWhereClause) then
    Self.AllowWhereSQL:=True;
  if (MaxRecords>0) then
  begin
    for i:=0 to aTableRequestInfoArray.Count-1 do
      aTableRequestInfoArray[i].MaxRecords:=MaxRecords;
  end;
  Result:=GetData(aTableNameArray,aTableRequestInfoArray);
end;

afbeelding

We are using RO10.0.0.1537. Both the client and the server are in delphi

Note: When I don’t use our custom OffGetData function the leak does not appear to be there.
How can we override GetData and make sure we free all the memory after the call?

Hi,

Have you modify aTableRequestInfoArray array inside CheckAddUserFilter or AppendUserFilter ?

if yes, these TableRequestInfoV5 are leaked.
You can do simple test:

function TTPEService.OffGetData(const aTableNameArray:StringArray;const aTableRequestInfoArray:TableRequestInfoArray;
   const MaxRecords:Integer;const StatementName,StatementSuffix,OrderClause:String;const PrfPrimkey:Integer;
   const SecurityContext,ExtraWhereClause:String):Binary;
var
  i:integer;
begin
{
  if SecurityService().CheckAddUserFilter(aTableNameArray,aTableRequestInfoArray,PrfPrimkey,SecurityContext) then
    Self.AllowWhereSQL:=True;
  if AppendUserFilter(aTableRequestInfoArray,ExtraWhereClause) then
    Self.AllowWhereSQL:=True;
  if (MaxRecords>0) then
  begin
    for i:=0 to aTableRequestInfoArray.Count-1 do
      aTableRequestInfoArray[i].MaxRecords:=MaxRecords;
  end;
}
  Result:=GetData(aTableNameArray,aTableRequestInfoArray);
end;

no memory leaks should be here.

I have done this test. The leak remains

Hi,

Can you create the simple testcase that reproduces this issue, pls?
you can drop email to support@ for keeping privacy.

OK, I have sent you a mail. The simple test application does not leak the RO XML but it does leak the TableRequestInfo

Hi,

I can’t detect any memory leaks on server-side with your testcase

Do you have fastmm active?

Hi,

yes, I’ve added FastMM5 as a 1st unit of project and added this line to .dpr:

ReportMemoryLeaksOnShutdown := True;

Were you able to run the sample with the fastmm4 that I included?

FYI: This is what I get with fastmm5
afbeelding

Hi,

I’ve compared our _Invk files and detected that you are using outdated version of DA:

this change causes memory leaks at your side.

try to use codegen4 or ServiceBuilder for generating _Invk

How can it be that I am using an outdated version?

The invk file was automatically generated from the RAD Studio IDE.
I have just deleted the file and regenerated it but the cleanup code is missing.
How can we determine which DA tools are used from the IDE?

Note: We have a modified RemObjects.inc

openend rodl file in service builder V10.0.0.1549
if i use the delphi codegen in the service builder and look at the code the objectdisposer adds are missing to…
__Message.InitializeResponseMessage(__Transport, ‘OffServerLibrary’, __Message.InterfaceName, ‘XLSGetDataSetDataResponse’);
__Message.ApplyAttributes2_Transport(__Transport);
__Message.Write(‘Result’, System.TypeInfo(Binary), lResult, []);
__Message.Finalize();

finally
__lintf := nil;
__lObjectDisposer := TROObjectDisposer.Create(__Instance);
try
__lObjectDisposer.Add(lResult);
finally
FreeOrDisposeOf(__lObjectDisposer);
end;

Hi,

Can you check TTPEService_Invoker.Invoke_OffGetData method, pls?

We are missing the cleanup code

can we check something in remobjects.inc file?
afaics:
{$IFDEF DELPHI_or_MSWINDOWS}
// use codegen4 instead of codegen1
{$DEFINE CODEGEN4}

Yes, we have that statement

{$INCLUDE eDefines.inc}

{ Define to check for RemObjects SDK 3.0 [vs. future versions] }
{.$DEFINE ROSDK4}
{.$DEFINE ROSDK5}
{.$DEFINE ROSDK6}
{.$DEFINE ROSDK7}
{.$DEFINE ROSDK8}
{.$DEFINE ROSDK9}
{$DEFINE ROSDK10}

{ Define to check for RemObjects SDK 3.0 and above [vs. older versions] }
{$DEFINE ROSDK3UP}
{$DEFINE ROSDK4UP}
{$DEFINE ROSDK5UP}
{$DEFINE ROSDK6UP}
{$DEFINE ROSDK7UP}
{$DEFINE ROSDK8UP}
{$DEFINE ROSDK9UP}
{$DEFINE ROSDK10UP}

{ use design ide packages only for Win32}
{$IFNDEF WIN32}
  {$DEFINE RemObjects_NO_DEMANDLOAD_FIX}
{$ENDIF}

{ DXSock }

    { To use RemObjects with the standalone version of DXSock, simply remove the
      define below. Note that this has only been tested with DXSock 3.0, and that
      doing so requires a separate license for DXSock from Brain PatchWorks
      see http://www.bpdx.com for more information }

    {$DEFINE RemObjects_USE_RODX}

{ Internet Component Suite (ICS) }
    { Internet Component Suite - http://www.overbyte.be }

    {.$DEFINE RemObjects_ICS_v5}
    {.$DEFINE RemObjects_ICS_v6up}

  {$IFDEF RemObjects_ICS_v5}{$DEFINE RemObjects_GLOBAL_ICS_DEFINE}{$ENDIF}
  {$IFDEF RemObjects_ICS_v6up}{$DEFINE RemObjects_GLOBAL_ICS_DEFINE}{$ENDIF}

  {$IFNDEF RemObjects_GLOBAL_ICS_DEFINE}
    {$UNDEF RemObjects_ICS_v5}
    {$UNDEF RemObjects_ICS_v6up}
    {$IFDEF Delphi7UP}
      {$DEFINE RemObjects_ICS_v6up}
    {$ELSE}
      {$DEFINE RemObjects_ICS_v5}
    {$ENDIF}
  {$ENDIF}


{ Indy }
   { If you are using Indy 10.6.2 (2016-01-16 and later) or the latest just uncomment the
     RemObjects_INDY10E DEFINE right below, and remove the Indy
     package references from the Requires section of RemObjects_Indy_Dx.dpk
     before re-compiling your RemObjects Indy package. }

  {.$DEFINE RemObjects_INDY10E}
  {$IFDEF RemObjects_INDY10E}
    {$DEFINE RemObjects_INDY10}
    {$DEFINE RemObjects_INDY10B}
    {$DEFINE RemObjects_INDY10C}
    {$DEFINE RemObjects_INDY10D}
    {$DEFINE RemObjects_GLOBAL_INDY_DEFINE}
  {$ENDIF}



   { If you are using Indy 10.5.9 or the latest just uncomment the
     RemObjects_INDY10D DEFINE right below, and remove the Indy
     package references from the Requires section of RemObjects_Indy_Dx.dpk
     before re-compiling your RemObjects Indy package. }

  {.$DEFINE RemObjects_INDY10D}
  {$IFDEF RemObjects_INDY10D}
    {$DEFINE RemObjects_INDY10}
    {$DEFINE RemObjects_INDY10B}
    {$DEFINE RemObjects_INDY10C}
    {$DEFINE RemObjects_GLOBAL_INDY_DEFINE}
  {$ENDIF}

   { If you are using Indy 10.2.3 or the latest just uncomment the
     RemObjects_INDY10C DEFINE right below, and remove the Indy
     package references from the Requires section of RemObjects_Indy_Dx.dpk
     before re-compiling your RemObjects Indy package. }

  {.$DEFINE RemObjects_INDY10C}
  {$IFDEF RemObjects_INDY10C}
    {$DEFINE RemObjects_INDY10}
    {$DEFINE RemObjects_INDY10B}
    {$DEFINE RemObjects_GLOBAL_INDY_DEFINE}
  {$ENDIF}

  { If you are using Indy 9 in Delphi 2005-2007, just uncomment the
     RemObjects_INDY9_in_Delphi2007 DEFINE right below}

  {.$DEFINE RemObjects_INDY9_in_Delphi2007}

  {$IFNDEF RemObjects_GLOBAL_INDY_DEFINE}

    {$UNDEF RemObjects_INDY8}
    {$UNDEF RemObjects_INDY9}
    {$UNDEF RemObjects_INDY10}

    {$IFDEF FPC}
      {$DEFINE RemObjects_INDY10}
      {$DEFINE RemObjects_INDY10B}
      {$DEFINE RemObjects_INDY10C}
      {$DEFINE RemObjects_INDY10D}
      {$DEFINE RemObjects_INDY10E}
    {$ELSE}
      {$IFDEF DELPHI23UP}
        {$DEFINE RemObjects_INDY10}
        {$DEFINE RemObjects_INDY10B}
        {$DEFINE RemObjects_INDY10C}
        {$DEFINE RemObjects_INDY10D}
        {$DEFINE RemObjects_INDY10E}
      {$ELSE}
        {$IFDEF DELPHI18UP}
          {$DEFINE RemObjects_INDY10}
          {$DEFINE RemObjects_INDY10B}
          {$DEFINE RemObjects_INDY10C}
          {$DEFINE RemObjects_INDY10D}
        {$ELSE}
          {$IFDEF DELPHI17UP}
            {$DEFINE RemObjects_INDY10}
            {$DEFINE RemObjects_INDY10B}
            {$DEFINE RemObjects_INDY10C}
            {$DEFINE RemObjects_INDY10D}
            {$DEFINE RemObjects_INDY10D_XE3}
          {$ELSE}
            {$IFDEF DELPHI12UP}
              {$DEFINE RemObjects_INDY10}
              {$DEFINE RemObjects_INDY10B}
              {$DEFINE RemObjects_INDY10C}
            {$ELSE}
              {$IFDEF DELPHI10UP}
                {$IFDEF RemObjects_INDY9_in_Delphi2007}
                   {$DEFINE RemObjects_INDY9}
                {$ELSE}
                  {$DEFINE RemObjects_INDY10}
                  {$DEFINE RemObjects_INDY10B}
                {$ENDIF}
              {$ELSE}
                {$IFDEF DELPHI9UP}
                  {$IFDEF RemObjects_INDY9_in_Delphi2007}
                    {$DEFINE RemObjects_INDY9}
                  {$ELSE}
                    {$DEFINE RemObjects_INDY10}
                    {$DEFINE RemObjects_INDY10A}
                  {$ENDIF}
                {$ELSE}
                  {$IFDEF DELPHI7UP}
                    {$DEFINE RemObjects_INDY9}
                  {$ELSE}
                    {$DEFINE RemObjects_INDY8}
                  {$ENDIF}
                {$ENDIF}
              {$ENDIF}
            {$ENDIF}
          {$ENDIF}
        {$ENDIF}
      {$ENDIF}

      {$IFDEF KYLIX}
        {$IFDEF KYLIX3UP}
          {$DEFINE RemObjects_INDY9}
        {$ELSE}
          {$DEFINE RemObjects_INDY8}
        {$ENDIF}
      {$ENDIF}
    {$ENDIF}

    { If you are using Indy 9 in Delphi 6 just uncomment the Indy9 DEFINE below,
      and remove the Indy package references from the Requires section of
      RemObjects_Indy_D6.dpk before compiling your RemObjects Indy package. }

    {.$DEFINE RemObjects_INDY9}

    {$IFDEF RemObjects_INDY9}
      {$UNDEF RemObjects_INDY8}
    {$ENDIF}

  {$ENDIF}

    { If you are using a newer version of Indy that properly works at designtime,
      you can set define the define below. If the define is not set (as is the
      default), Indy channels cannot be used to connect at designtime, trying so
      will display a warning message.

      If you enable this define and receive an Access Violation when trying to
      connect at designtime, then your Indy version does not yet include the
      fix for this problem. Please contact the Indy Crew for details.

      This problem applies to the Delphi Windows IDE's only; Kylix is not affected. }

    {$DEFINE RemObjects_INDY_DESIGNTIME_FIX}

{ Thread Names in Debugger }

    {$IFDEF DELPHI7UP}
      {$IFDEF MSWINDOWS}
        {$DEFINE RemObjects_SetThreadName}
      {$ENDIF}
    {$ENDIF}

{ XML }

    {$IFDEF MSWINDOWS}
      {$DEFINE RemObjects_MSXML}
    {$ELSE}
      {$IFDEF NEXTGEN}
        {$DEFINE RemObjects_NextGenXML}
      {$ELSE}
        {$DEFINE RemObjects_OpenXML}
      {$ENDIF}
    {$ENDIF}

    { if we someone manually defined RemObjects_OpenXML, then undef RemObjects_MSXML }
    {$IFDEF RemObjects_OpenXML}
      {$UNDEF RemObjects_MSXML}
    {$ENDIF}


    {$IFDEF FPC}
      {$MODE DELPHI}
      {$DEFINE RemObjects_OpenXML}
      {$UNDEF RemObjects_MSXML}
    {$ENDIF}

    {$IFDEF RemObjects_NextGenXML}
      {$UNDEF RemObjects_OpenXML}
      {$UNDEF RemObjects_MSXML}
    {$ENDIF}

{ mac osx}
    {$IFDEF FPC_OSX}
      {$DEFINE RemObjects_OSX_FPC}
      {$DEFINE RemObjects_OSX}
    {$ENDIF}
    {$IFDEF DELPHI_OSX}
      {$DEFINE RemObjects_OSX_DELPHI}
      {$DEFINE RemObjects_OSX}
      {$DEFINE RemObjects_OSX_or_Android_or_Linux_DELPHI}
    {$ENDIF}

{ android}
    {$IFDEF DELPHI_ANDROID}
      {$DEFINE RemObjects_ANDROID}
      {$DEFINE RemObjects_ANDROID_DELPHI}
      {$DEFINE RemObjects_OSX_or_Android_or_Linux_DELPHI}
    {$ENDIF}

{linux}
    {$IFDEF DELPHI_LINUX}
      {$DEFINE RemObjects_LINUX}
      {$DEFINE RemObjects_LINUX_DELPHI}
      {$DEFINE RemObjects_OSX_or_Android_or_Linux_DELPHI}
    {$ENDIF}
    {$IFDEF FPC_LINUX}
      {$DEFINE RemObjects_LINUX}
      {$DEFINE RemObjects_LINUX_FPC}
    {$ENDIF}

 {$Q-,B-,R-}

{ Zlib support }
{$IFDEF DELPHIXE2UP}
  {$DEFINE USE_NATIVE_ZLIB}
{$ENDIF}

{ VCL package }
{$IFDEF DELPHIXE2UP}
  {$DEFINE RemObjects_VCL_Package}
{$ENDIF}

{$IFDEF NEXTGEN}
  {$LEGACYIFEND ON}
{$ENDIF}

{ Format Settings }
{$IFDEF DELPHI15UP}
  {$DEFINE Use_FormatSettings}
{$ENDIF}

{$IFDEF FPC}
  {$DEFINE Use_FormatSettings}
{$ENDIF}

{$IFDEF DELPHIXE3UP}
  // server-side only
  {$DEFINE RO_RTTI_Support}
  // convert services (_impl) in wizard
  {$DEFINE CodeFirst_Wizard_Convert_impl}
  // generate uses section in generated RODL
  // useful for DA services
  {$DEFINE CodeFirst_Use_RODL_Uses}
  // generate all services, including abstract one
  // useful for DA services
  {$DEFINE CodeFirst_Generate_Abstract_Services}
{$ENDIF}

{$IFDEF DELPHI_or_MSWINDOWS}
  // use codegen4 instead of codegen1
  {$DEFINE CODEGEN4}
  // codegen4: generate full qualified names in _Intf for Delphi
  {.$DEFINE CODEGEN4_GENERATE_FULL_QUALIFIED_NAMES}
  // codegen4: include {$SCOPEDENUMS ON} into _Intf for Delphi
  {.$DEFINE CODEGEN4_SCOPEDENUMS}
  // codegen4: use AnsiString/UTF8Strings
  {.$DEFINE CODEGEN4_LEGACYSTRINGS}
  // generate _Intf and _Impl with CodeFirst attributes. can be used for easily
  // migration or switching between RODL-based services or CodeFirst based ones
  {.$DEFINE CODEGEN4_CODEFIRSTCOMPATIBLE}
  // skip generation of generic arrays in _Intf
  {.$DEFINE CODEGEN4_SKIPGENERICARRAYS}
  
  // generate only for XE2+ or for D7-XE, FPC
  // both undefined - generate compatible code
  {.$DEFINE CODEGEN4_DelphiXE2UP_On}
  {.$DEFINE CODEGEN4_DelphiXE2UP_Off}
  
  // generate only for FPC or only for Delphi
  // both undefined - generate compatible code
  {.$DEFINE CODEGEN4_FPC_On}
  {.$DEFINE CODEGEN4_FPC_Off}
  
  // generate CodeFirst only or RODL based code
  // both undefined - generate compatible code
  {.$DEFINE CODEGEN4_CodeFirst_On}
  {$DEFINE CODEGEN4_CodeFirst_Off}
  
  // generate with or w/o GenericArray support
  // both undefined - generate compatible code
  {.$DEFINE CODEGEN4_GenericArray_On}  
  {.$DEFINE CODEGEN4_GenericArray_Off}

  {$IFDEF FPC}
    {$DEFINE CODEGEN4_CodeFirst_Off}
    {$DEFINE CODEGEN4_GenericArray_Off}
    {$UNDEF CODEGEN4_CODEFIRSTCOMPATIBLE}
  {$ENDIF}
{$ENDIF}

// uncomment this line if you have errors like 'Unknown method XXXX for interface YYYY'
// after upgrading from RO8.1- to RO8.2+
{$DEFINE TROPROXY_IGNORES_REMOTESERVICE_SERVICENAME}

//for backward compatibility, use only if _Intf.pas can't be regenerated and produced errors
{.$DEFINE TROArray_BackwardCompatibility}


// enable usage of AnsiString & UTF8String for NEXTGEN compiler as type of string
{.$DEFINE ROLegacyStringTypesInNEXTGEN}

{$IFNDEF NEXTGEN}
  {$UNDEF ROLegacyStringTypesInNEXTGEN}
{$ENDIF}

{$IFDEF NEXTGEN}
  {$IFDEF ROLegacyStringTypesInNEXTGEN}
    {$DEFINE ROAllowLegacyStringTypes}
  {$ENDIF}
{$ELSE}
  {$DEFINE ROAllowLegacyStringTypes}
{$ENDIF}

{$IFDEF DELPHIXE6UP}
  {$DEFINE ROUseGenerics} // optionally
{$ENDIF}
{$IFDEF NEXTGEN}
  {$DEFINE ROUseGenerics} // required!
{$ENDIF}

{$IFDEF ROUseGenerics}
  // twice slower in comparing with sensitive comparing!
  // for backward compatibility, non-case sensitive comparing is used
  {$DEFINE TDictionary_NonCaseSensivite_Comparing}
{$ENDIF}

{$IFDEF MSWINDOWS}
  {$IFDEF FPC}
    {$DEFINE WINSOCK2_PRESENT}
  {$ENDIF}
  {$IFDEF DELPHIXEUP}
    {$DEFINE WINSOCK2_PRESENT}
  {$ENDIF}
{$ENDIF}
{$IFDEF MSWINDOWS}{$DEFINE RemObjects_UseEncryption}{$ENDIF}
{$I RemObjects_user.inc}

Hi,

Your RemObjects.inc is ok.
can you show RemObjects_user.inc too, pls?


is it possible to install the latest DAD to clean VM and generate _Invk with Service Builder for TestDAServerLibrary.rodl (from testcase you have sent to us )?

the remobjects_user.inc is empty