RTC Forums

Subscription => Support => Topic started by: Aeter on July 31, 2018, 05:37:42 PM



Title: Session: Memory Leak
Post by: Aeter on July 31, 2018, 05:37:42 PM

Hello,
looking at the code I realized that by calling the function CloseSessionID the sessions are closed but the RAM is never released because the sessions are always in the SessLockList list.

How I can resolve this memory leak?

From rtcDataSrv.pas :

Code:
function CloseSessionID(const ID,PeerAddr,ForwardedFor: RtcString; _Event:TRtcSimpleEvent):boolean;
  var
    id2:RtcString;
    o:TObject;
    sess:TRtcServerSession;
  begin
  if ID='' then
    Result:=false
  else
    begin
    SessCS.Acquire;
    try
      if assigned(SessUnLockList) then
        begin
        id2:=ID;
        {$IFNDEF UseGUIDs}
        // Set ID to desired length, so it will be sorted as a numeric value.
        while length(id2)<RTC_SESSIONID_LENGTH do
          id2:=' '+id2;
        {$ENDIF}

        // Find Session with Session ID inside unlocked sessions list
        o:=SessUnLockList.search(id2);
        if o<>nil then
          begin
          sess:=TRtcServerSession(o);
          // Check if we have the right to access this session
          if sess.DenyAccess(PeerAddr,ForwardedFor) then
            Result:=False
          else
            begin
            // Remove from UnLocked list
            SessUnLockList.remove(id2);
            // Remove from Expiring list
            SessExpList.remove(SessionTimeToStr(sess.ExpireTime)+sess.ID);
            // Call SessionClose event.
            if assigned(_Event) then
              _Event(sess);
            // Free session object
            RtcFreeAndNil(sess);
            Result:=True;
            end;
          end
        else
          begin
          // Find Session with Session ID inside Locked Sessions list
          o:=SessLockList.search(id2);
          if o<>nil then
            begin
            sess:=TRtcServerSession(o);
            // Check if we have the right to access this session
            if sess.DenyAccess(PeerAddr,ForwardedFor) then
              Result:=False
            else
              begin
              sess.FinalExpire:=Now;
              Result:=True;
              end;
            end
          else
            Result:=False;
          end;
        end
      else
        Result:=False;
    finally
      SessCS.Release;
      end;
    end;
  end;


Title: Re: Session: Memory Leak
Post by: D.Tkalcec (RTC) on July 31, 2018, 06:28:36 PM
Expired and/or Closed Sessions can ONLY be released from Memory if they are "unlocked" (NOT referenced by another RTC component).

If you close a "Locked" Session (the Session is still referenced by a RTC connection component), the Session object will be marked as "Expired", but it will NOT be released from Memory, as long as the Session remains "Locked".

If you have manually locked a Session (for example, by calling the "FindSession" or "OpenSession" method), you can unlock your Session by using the "UnLockSession" method (used on the same component where "FindSession" or "OpenSession" was used to lock the Session).

If a Session was locked automatically by a RTC component (for example, a "TRtcServerModule" with Automatic Sessions), the Session will be unlocked by that same component, once it is no longer needed to complete processing the request (response was prepared or connection closed).


Title: Re: Session: Memory Leak
Post by: Aeter on August 01, 2018, 08:39:04 AM
Sessions are automatically locked, but then they never come unlocked and therefore the memory remains available but occupied by the component for the whole life of the program.When the client disconnects the server (TRtcBaseServerModule) it must release all the resources occupied by it.


Title: Re: Session: Memory Leak
Post by: D.Tkalcec (RTC) on August 01, 2018, 08:42:23 AM
Where did you get that idea from? If that were the case, then it would be a bug.

Can you post a short example Project reproducing this behavior?


Title: Re: Session: Memory Leak
Post by: Aeter on August 01, 2018, 09:12:38 AM
I have set autosessions to true and then the sessions manage them automatically.
The problem is that when I call TRtcConnection.CloseSession (id) to close the session, It set sess.FinalExpire:=Now but then the session is never release.When I put the program in debug and I see that It never run this instruction that would free the memory:

Code from rtcDataSrv.pas ( line 2008-2028)
Code:
  o:=SessUnLockList.search(id2);
        if o<>nil then
          begin
          sess:=TRtcServerSession(o);
          // Check if we have the right to access this session
          if sess.DenyAccess(PeerAddr,ForwardedFor) then
            Result:=False
          else
            begin
            // Remove from UnLocked list
            SessUnLockList.remove(id2);
            // Remove from Expiring list
            SessExpList.remove(SessionTimeToStr(sess.ExpireTime)+sess.ID);
            // Call SessionClose event.
            if assigned(_Event) then
              _Event(sess);
            // Free session object
            RtcFreeAndNil(sess);
            Result:=True;
            end;
          end
        else


This happens because the session is set as expired but then it is no longer unlocked and released!


Title: Re: Session: Memory Leak
Post by: D.Tkalcec (RTC) on August 01, 2018, 09:21:13 AM
Can you post an actual example where Sessions are created and locked, but never get unlocked or released from Memory?

You keep posting a function which is NOT responsible for Session memory management, but only marks Sessions as expired. The method responsible for clearing up the Memory from expired sessions is "UnLockSession" and ... that method is called automatically in several places (search for "InitSesssion" method in the same unit, which calls "UnLockSession" if a Session is locked).

Code:
{ UnLock Session and remove all sessions that have expired:
   - remove from Locked list
   - add to UnLocked and Expiring list }
procedure TRtcServerSession.UnLockSession(_Event:TRtcSimpleEvent);
  var
    id2,ex:RtcString;
    o:TObject;
  begin
  if not assigned(SessCS) then Exit;

  SessCS.Acquire;
  try
    if assigned(SessUnLockList) then
      begin
      // Check if there are Sessions that have expired but are still in our session list
      ex:=SessExpList.search_min(o);
      while (ex<>'') and (TRtcServerSession(o).ExpireTime<=Now) do
        begin
        // Remove from Expiring list
        SessExpList.remove(ex);

        // Set ID to desired length, so it will be sorted as a numeric value.
        id2:=TRtcServerSession(o).ID;
        {$IFNDEF UseGUIDs}
        while length(id2)<RTC_SESSIONID_LENGTH do
          id2:=' '+id2;
        {$ENDIF}

        // Remove from UnLocked list
        SessUnLockList.remove(id2);

        if assigned(_Event) then
          _Event(o);
        // Free the Session object
        RtcFreeAndNil(o);

        ex:=SessExpList.search_min(o);
        end;

      id2:=FID;
      {$IFNDEF UseGUIDs}
      // Set ID to desired length, so it will be sorted as a numeric value.
      while length(id2)<RTC_SESSIONID_LENGTH do
        id2:=' '+id2;
      {$ENDIF}

      // Remove from Locked list
      SessLockList.remove(id2);

      // Free if expired, add to expiring list if not.
      if ExpireTime<=Now then
        begin
        if assigned(_Event) then
          _Event(self);
        {$IFDEF NEXTGEN} DisposeOf; {$ELSE} Free; {$ENDIF}
        end
      else
        begin
        // Add to UnLocked list
        SessUnLockList.insert(id2, self);
        // Add to Expiring list
        SessExpList.insert(SessionTimeToStr(ExpireTime)+ID, self);
        end;
      end;
  finally
    SessCS.Release;
    end;
  end;


Title: Re: Session: Memory Leak
Post by: Aeter on August 01, 2018, 09:35:24 AM
The code is quite complex, however when a client disconnect from server this function is performed:

Code:

procedure TGateway.LogOutEx(Sender: TRtcConnection; Param: TRtcFunctionInfo; Result: TRtcValue);
var
  sClientType : string;
  sid,a:string;
  closed:boolean;
  i:integer;
begin
sid:= Sender.Session.ID;
  Sender.Session.asBoolean['login']:=False;   
  Sender.Session.Session.Clear;
  closed:=Sender.CloseSession(sid);
  Sender.Session.Close;
  if closed and writelog then
xLog('Session '+sid+' closed '+' Total session remains :'+intToStr(Sender.TotalSessionsCount));

end;

I can assure you that the UnLockSession function never (NEVER) runs despite the session being closed!!


Title: Re: Session: Memory Leak
Post by: Aeter on August 01, 2018, 09:40:02 AM
I did some tests, if you connect 100 clients, 60 MB of memory is occupied, but when they are disconnected, the memory remains busy.
If you reconnect them all and 100 no more memory is added, but if you connect 200 120MB of memory are occupied .. and so on

I think this happens because the program knows that that portion of memory occupied by expired sessions is free, but does not release it!


Title: Re: Session: Memory Leak
Post by: D.Tkalcec (RTC) on August 01, 2018, 09:54:19 AM
You can check how many Sessions are still in Memory with "TotalSessionsCount", "TotalSessionsLocked" and "TotalSessionsUnlocked" methods, which are all available on the "Sender:TRtcConnection" component (passed to all RTC components events).

If you want to debug Session management, make sure you are using more than one Session, because the expiration time of a Session is automatically extended each time you try to access that Session. This is by design, to avoid Sessions being released from Memory just before they are needed (since that would be counter-productive). In other words, expired and closed Sessions would ONLY be released from Memory when another Session is unlocked, which can NOT happen if you only use a single Session.

Also, do NOT use the Windows Task Manager to check how much RAM your Application is using, because Delphi Applications use a Memory Manager which allocates RAM from the OS in large blocks, then manages memory allocations inside these blocks for you. If you are unfamiliar with Memory Management in Delphi, try googling "Delphi Memory Management" or "delphi fastmm".


Title: Re: Session: Memory Leak
Post by: Aeter on August 01, 2018, 10:49:44 AM
I use ProcessHacker to monitor the RAM and I've done both test with the program in debugging and in running mode.
The problem is that on 100 open and then closed sessions none is permanently destroyed by executing the RtcFreeAndNil (o) statement (line 3905 of rtcDataSrv.pas).
In fact, the component then, when other connections arrive reuses that busy ram, but I would like when there is a disconnection the ram used for that session is deallocated.


Title: Re: Session: Memory Leak
Post by: D.Tkalcec (RTC) on August 01, 2018, 10:59:38 AM
I think you really should read about Memory Management in Delphi before you continue making assumptions. Also, if you are looking for a place to put a break-point, so you can see when RTC Session objects are being released from Memory and destroyed, open the "rtcInfo.pas" unit and find the "TRtcSession.Destroy" method there, then place a break-point at the line where FID and FPeerAddr variables are cleared. This should be line 31972 if you are using the latest RTC SDK version ...

Code:
destructor TRtcSession.Destroy;
  begin
  try
    // {$IFDEF RTC_EXTDEBUG}Log('TRtcSession.Destroy "'+FID+'" ('+FPeerAddr+')','DEBUG');{$ENDIF}
    FID:=''; FPeerAddr:=''; // <- place a breakpoint on THIS line!
    inherited;
    // {$IFDEF RTC_EXTDEBUG}Log('TRtcSession.Destroyed.','DEBUG');{$ENDIF}
  except
    on E:Exception do
      begin
      if LOG_AV_ERRORS then
        Log('TRtcSession.Destroy',E,'ERROR');
      raise;
      end;
    end;
  end;


Title: Re: Session: Memory Leak
Post by: Aeter on August 01, 2018, 11:38:34 AM
I put the break point there (line 31971 of RTCInfo.pas) and in fact the component destroys the Session object, but the fact remains that the memory remains busy !!


Title: Re: Session: Memory Leak
Post by: D.Tkalcec (RTC) on August 01, 2018, 12:05:19 PM
Delphi Memory Management. Read about it. Seriously.


Title: Re: Session: Memory Leak
Post by: Aeter on August 01, 2018, 01:08:34 PM
Could you try to see if there is a memory leak with connections (many connections) on TRtcBaseServerModule?


Title: Re: Session: Memory Leak
Post by: D.Tkalcec (RTC) on August 01, 2018, 01:35:40 PM
Done. No Memory Leaks found.