Session memory leaks in 9.4

I’ve recently upgraded to the latest March 2018 release of DA for Delphi and I seem to be getting some memory leaks.

These are UnicodeString, TROSession and TROVariantList types/objects which all seem to trace back to the TROCustomSessionManager.CreateSession function.

I know some changes have been made in 9.4, specifically the fSessionList property has been changed from a TStringList to a generic. Has a leak crept in somewhere here as I don’t think I’ve changed anything in my code?

I can’t reproduce this issue. FastMM4 doesn’t report any memory leaks.

can you create a simple testcase that reproduces this issue, pls?
you can attach it here or send directly to support@

I very much doubt I can as it’s in the bowels of my server. Basically when my server needs to do autonomous stuff (i.e. not in response to an authenticated client which already has a session), it calls the CreateSession function to create a session for its own use.

For some reason it looks like this session isn’t being properly freed any longer as the leaks all seem to pertain to the session object itself and the properties assigned to it (the UnicodeStrings).

I’ll carry on digging.

how do you create and release this session on your server side?

Ok, I’ve just forced fSessionsList back to using the old TStringList logic and the problem disappears - no leaks.

However I do have some helper functions which I did have to modify slightly for this change (and revert these changes when I forced it back to TStringList functionality) so it may be that something these functions of mine are doing is now causing the leak.

I’m continuing to investigate.

you could just disable {$DEFINE ROUseGenerics} in RemObjects.inc for using non-generic version…

Yes I could but I’d like to find the root of the problem.

To answer your previous question, I create the session via a call to the sessionmanager’s CreateSession function but I don’t explicitly free/destroy it as the server will often make repeated use of it so I just leave it to expire “naturally” if it’s not used for a while. I keep track of the GUID and, each time I need a session, I check if it’s still present and not expired - if it is then I’ll re-create it.

have you released it, like

    s:=ServerDataModule.SessionManager.CreateSession(ServerDataModule.LocalDataAdapter.SessionID);
    s['a'] := '''AROUT''';
    ServerDataModule.SessionManager.ReleaseSession(s,True);

?

No, I was just thinking that - I never release it, should I do so when I’m done with it?

I think I didn’t do that originally because I thought releasing it would render it unusable again so each time I’d have to create a new session. Is that the case or will it still remain there and usable until the idle timeout expires?

yes, you need to release it, otherwise it won’t be added into fSessionList (in case of TROInMemorySessionManager) and won’t be freed automatically at destroying SessionManager.

Ok I’ll try that and see how it works - so even releasing it won’t actually delete it and it’ll still be re-usable before it’s expired?

 ServerDataModule.SessionManager.ReleaseSession(s,True);

this adds this session into list of known sessions that can be expired later and yes - it still re-usable, but in some cases, you need to reacquire it.

Note: if you don’t call ReleaseSession, you have to destroy this session manually.

Well I’ve just done that and, as soon as I started my server, FastMM4 threw up an error that a block had been modified after being freed.

The stack trace showed that the block was freed in response to the ReleaseSession call, so it appears it is actually destroying the session object at this point?

Looking at TROInMemorySessionManager.DoReleaseSession, if NewSession is True then it’s calling aSession.DisposeOf, which is the point at which the session is freed.

from

procedure TROInMemorySessionManager.DoReleaseSession(aSession: TROSession; NewSession : boolean);
..
    if not fSessionList.ContainsKey(aSession.SessionID) then
      fSessionList.Add(aSession.SessionID, aSession)
    else
      aSession.DisposeOf;

Session will be freed only if it is present in fSessionList.
by default, only DoReleaseSession adds the session into this list, unless your helpers do this already

Ok I’m totally lost now.

I thought fSessionList was the list of all sessions but now you’re saying that session may exist but not be in this list?

Furthermore it seems that ReleaseSession is responsible for adding sessions to fSessionList which seems totally counter-intuitive.

logic is following:

  • Session is usually created in Login method, but not added to session manager in CreateSession method.
  • if something is wrong, DestroySession can be called
  • when Login call is finished and DestroySession wasn’t called, session will be added to session manager in TRORemoteDataModule.DoOnDeactivate.
  • this guarantees that nobody can access to server using this session until Login method isn’t finished.

about methods names - it was named 15+ years ago
also this stuff is usually used internally only

Ok thanks.

So basically it looks like ReleaseSession is used to (optionally) add a session to the session manager if it’s called once. If it’s called a second time then it removes it from the manager AND destroys the session immediately, is this correct?

I’ve checked my code and I must have tangled with this before (can’t remember now) as I am indeed calling ReleaseSession to add my new session to the manager. That’s obviously why a subsequent call to ReleaseSession is causing the object to be freed.

Standard sessions created in response to client logins are all working fine. The issue I have is that my server needs to create its own sessions to perform some autonomous internal functions, as these functions will make use of services for which a session is required.

I guess the most basic question is, therefore, do such sessions NEED to be added to the manager in order to work correctly, or can a session which has never been added to the manager (via a ReleaseSession call) work fine despite this?

Going back to my original code, i.e. ignoring the change I just tried above…

I am creating these sessions and then adding them to the session manager via ReleaseSession.

I am never freeing/destroying these sessions manually, I simply leave them in the manager. When I need a session to do some work, I see if there’s an unexpired one in the manager, in which case I use that (which prolongs it’s life) or else I create a new one.

I’ve never had any problems nor memory leaks doing this until now and I can’t figure out why I suddenly am. As the sessions are added to the manager, they should all be destroyed when the application closes, specifically via TROInMemorySessionManager.Destroy calling ClearSessions(FALSE).

Was your previous advice that I had to free these sessions based on the assumption that I hadn’t added them to the manager?

if you added session to SessionManager via ReleaseSession then it will be freed automatically
if you doesn’t use ReleaseSession then you need to destroy this session manually.