Sessions and Memory Leaks

I notice that the Session Count of my Web app stays nice and low for a couple days, with it clearly dropping as user sessions die out. Then, after a couple days, the Session Count rises and rises, even when user sessions have supposedly timed out. Reading posts on this forum makes me think this is a memory leak, most likely caused by a circular reference.

I imagine the most likely culprit is a Session property called MailSocket1, which points to an SMTPSecureSocket created in Session.Open. Can I simply place this in Session.Close to handle this? …

Self.MailSocket1 = Nil

[quote=272685:@Ralph Alvy]I notice that the Session Count of my Web app stays nice and low for a couple days, with it clearly dropping as user sessions die out. Then, after a couple days, the Session Count rises and rises, even when user sessions have supposedly timed out. Reading posts on this forum makes me think this is a memory leak, most likely caused by a circular reference.

I imagine the most likely culprit is a Session property called MailSocket1, which points to an SMTPSecureSocket created in Session.Open. Can I simply place this in Session.Close to handle this? …

Self.MailSocket1 = Nil

No. Session.Close fires too late for that. I’d suggest setting that to Nil when you’re truly done with it.

That said, unless your MailSocket has a property that points to the Session, this probably isn’t the cause of your troubles.

Thanks, as usual, Greg.

MailSocket1 is an instance of MailSocket, which is subclassed from SMTPSecureSocket. MailSocket has a computed property called Session (As Session).

Its Get is

If mSession = Nil or mSession.value = Nil Then Return Nil else Return Session(mSession.Value) End If

Its Set is

mSession = New WeakRef(value)

And mSession is of type WeakRef

Since the above MailSocket property references Session, albeit weakly, I’m now creating the socket only as needed, and setting it to Nil when not needed. I’ll see how that works.

Since mSession is a weakref, it is not your culprit.

Then, could it be that I do not explicitly close database connections when not needed? Those connections are created on Session.Open.

I’ll add this to Session.Close and see if that helps:

If DB.Connect Then DB.Close

Though I don’t see any circular referring going on here, so I expect you’re going to say it also is not my culprit.

I think I may have tracked down a major player in all this after reading https://forum.xojo.com/15980-web-session-memory-leak/0 and noticing Greg O’Lone’s comment:

I found I was using 2 WebPage properties to store Session.DB.LastRowID to make it “easier to code.” I replaced all usages of those properties with Session.DB.LastRowID and will see if that makes a difference.

Hmmm … the more I think about this, the above doesn’t seem like what Greg is talking about. The WebPage properties I found are not computed properties. They are updated my methods as needed.

[quote=272733:@Ralph Alvy]I’ll add this to Session.Close and see if that helps:

If DB.Connect Then DB.Close

Though I don’t see any circular referring going on here, so I expect you’re going to say it also is not my culprit.[/quote]
Don’t do this. You’re connecting to the database just to close it.

I realized that later and changed it to

If DB <> Nil Then DB.Close

I found I couldn’t just use

DB.Close

in Session.Close because it would sometimes give a Nil Object Exception.

a) Xojo will close the db for you
b) I would assume that session.close never happens on the sessions that don’t go away, so any code in session.close isn’t related to, nor will it fix, the problem.

Thanks, Tim. In terms of Session.Close, I was assuming that, after a couple days of the Web App running fine, when users start seeing the Disconnect Message (after timing out) while the Session Count doesn’t decrease, even after many hours, Session.Close was firing but somehow Xojo was just not releasing the session. That is, I assumed that, perhaps incorrectly, if that Disconnect Message appears, Session.Close ran.

But then I noticed http://documentation.xojo.com/index.php/Database.Close say

and Greg say in WebSession.Close issues - Web - Xojo Programming Forum

So I thought maybe the DB connection wasn’t closing in these situations and was keeping the session from closing, because I didn’t explicitly close it in Session.Close. In time mean time, I looking for any possible way I have circular references to Session, since this DB connection concern is sounding like a fool’s errand.

Going back to circular references, try doing a search for “as Session” in your project. If you have any of those as properties in any WebControl or WebView subclass, that would be the place to start. That said, Sessions are not the only things that cause leaks like this. Sessions keep an array of WebPages, Pages, Dialogs and Containers keep an array of WebControls and other WebViews. Any of the subcontrols that keep references to another object at the same level or above it within that same session could cause a leak.

Thanks for the detailed reply, Greg. It gives me a lot to go on.

When looking for objects that “keep references” to other objects, are such 'kept references" confined to computed properties? If so, I have none anywhere in the project except for a the WeakRef noted earlier in this post (the property MailSocket). Also, I have no methods that use the Assigns keyword, should that be relevant.

no
a plain property could be the culprit if its NOT a weak ref

So when a WebPage1 method sets WebPage1.MyProperty to Session.MyProperty, this is considered a “kept reference” and could cause a memory leak? I wouldn’t have thought that, since they are not logically linked like they would be if WebPage1.MyProperty was a computed property.

I have no idea why you would think that computed makes any difference

Any variable, property (computed or not as they are both properties), that is assigned an OBJECT reference (ie/ its not a string, integer, double etc) and its not a weak reference holds a hard reference. And if there happens to be a cycle of hard references this can cause a leak

For instance

Class A
    property refToSomeBInstance as ClassB
end class

Class B
    property refToSomeAInstance as ClassA
end class


dim Ainstance as new ClassA
dim Binstance as new ClassB

Ainstance.refToSomeBInstance = Binstance
Binstance.refToSomeAInstance = Ainstance

a = nil
b = nil

Since Ainstance refers to Binstance and Binstance refers to Ainstance when I set my local variables to nil the ONLY thing that will happen is that I cannot reference them any more. They wont be removed from memory.

Thats a leak

Ainstance has a reference to Binstance so keeps Binstance alive (its reference count ?0)
And Binstance has a reference to Ainstance so keeps Ainstance alive (its reference count ? 0)

And you have a nice leak