Memory leak in OracleQueue?

ldsandon

Member³
I switched from using queues with a RAW payload to queues with object payload (I hit the 32k limit of raw payloads). I defined an object as follows:

Code:
create or replace type IKON_SYSTEM.PM_ENGINE_MESSAGE as object (
    PROCESS_ID NUMBER,
    PROJECT_ID NUMBER,
    ENGINE_MESSAGE CLOB
);
I have two processes (sevices). One enqueues only, the other dequeues, processes data (ENGINE_MESSAGE stores an XML document with data to process) and optionally reenqueues one or more objects to be processed, if needed.
The code used is (TdmIkonSystem is my datamodule):

Code:
procedure TdmIkonSystem.Enqueue(const AMessage: string; AProcessID,
  AProjectID: Int64; const ASender: string; APriority: Integer);
begin
  try
    {$IFDEF RAW_PAYLOAD}
    Enqueuer.RawPayload := AMessage;
    {$ELSE}
    with Enqueuer.Payload do
    begin
      SetAttr('PROCESS_ID', AProcessID);
      SetAttr('PROJECT_ID', AProjectID);
      SetAttr('ENGINE_MESSAGE', AMessage);
    end;
    {$ENDIF}
    Enqueuer.MessageProperties.Priority := APriority;
    Enqueuer.MessageProperties.SenderId.Name := ASender;
    Enqueuer.Enqueue;
    Enqueuer.Session.Commit;
  except
    Enqueuer.Session.Rollback;
    raise;
  end;
end;
When using the object payload instead of the RAW ones, a memory leak appears that will "eat" all available memory soon. It disappear when I use RAW payloads. I tried several combinations of EnqueueOptions, and trying to commit after enqueueing the message, but nothing helped.

I observed that the process that only enqueues works ok, and if the other process only dequeues it works too. When this process starts to dequeue and enqueue (using two separate TOracleQueue objects, and usually in two separate datamodule instances with separate connections), the memory leak appears. Am I doing something wrong with objects, or is it a DOA leak?

May I ask also why "Payload" is generated internally, and not passed to the Enqueue function? I would have preferred something alike

Code:
Payload := Payload.Create(...)
   try
     Enqueue(Payload);
   finally
     Payload.Free;
   end;
 
Some additional informations. I was not able to prepare a small test case, therefore I started profiling my service with AQTime 4.40.481.0.

I saw a lot of "TOracleObject: Invalid handle" exceptions. What I did not say before is that the application is multi-threaded. Each thread instances its datamodule (with its own session and enqueuer), and destroys it on exit.
Here it is a dump from AQtime:

Code:
Event                                                                                                                                                                         Thread ID  Time
-  Exception 0x0EEDFADE Delphi exception occurred at 0x7C59BBF3 (class: Exception, message: "TOracleObject: Invalid handle")                                                  1760       14.45.05.742
                                                                 0x7C59BBF3 RaiseException + 0x56 in KERNEL32.DLL                                                             1760
                                                                 0x004EBFAC Oracle::TOracleObject::OCICall + 0x34 in IkonProcessManager.exe                                   1760
                                                                 0x004EBFAC Oracle::TOracleObject::OCICall + 0x34 in IkonProcessManager.exe                                   1760
                                                                 0x004EBD06 Oracle::TOracleObject::Destroy + 0xA2 in IkonProcessManager.exe                                   1760
                                                                 0x004040AB System::TObject::Free + 0xF in system.pas line 8386 in IkonProcessManager.exe                     1760
                                                                 0x004EFC35 Oracle::TOracleQueue::Destroy + 0x65 in IkonProcessManager.exe                                    1760
                                                                 0x00429843 Classes::TComponent::DestroyComponents + 0x6B in classes.pas line 9855 in IkonProcessManager.exe  1760
                                                                 0x00429557 Classes::TComponent::Destroy + 0x7B in classes.pas line 9758 in IkonProcessManager.exe            1760
                                                                 0x0042AE86 Classes::TDataModule::Destroy + 0x76 in classes.pas line 10782 in IkonProcessManager.exe          1760
                                                                 0x004040AB System::TObject::Free + 0xF in system.pas line 8386 in IkonProcessManager.exe                     1760
   Thread exit ID: 1760;  Exit code: 0                                                                                                                                        1760       14.45.05.820
   Thread create ID: 1760                                                                                                                                                     1760       14.45.06.117
It looks there is a problem when the Oracle Queue is destroyed but I can't undestand why.
 
Also, may I ask the reason of the empty except sections in TOracleQueue.Destroy? Hiding unhandled exceptions it's not a good programming practice, IMHO.
 
Further observations: it looks it does not happens if I do not "logoff" the TOracleSession in the OnDestroy event of the datamodule, but let the session destructor to logoff (hopefully). Are objects informations stored at the session level, somehow? That would explain why TOracleQueue will trigger an exception if the session is logged off before it is destroyed.
 
Thank you. Ah, those result were obtained with Delphi 7 UP1 and DOA 4.0.5/4.0.6.2 (tried both), Oracle 9.2.0.5, I forgot to add it before - was under a heavy pressure to fix it as soon as I could :D
 
Back
Top