Web app Session properties vs. WebPage properties

I’m kind of grasping at straws for what could be happening with my web app. Last week, I updated the app (hosted on Xojo Cloud). The only main difference I made with the app was the addition of a WebToolbar. I doubt that’s the problem as I’m sure many others are using toolbars without issue

The other day, I heard from a couple users that they would get kicked out of the app (goes back to the login page). I checked the memory usage, and it was shooting up there pretty quickly (about 180 MB, normally sits around 60 MB). Now, there was a lot of traffic on the app at that given time

Another point, and I’m not sure if this is normal, but I do occasionally check my server’s memory (once every couple of days). I usually need to restart my XC server about once a month when I see the memory getting up there (60% to 70% when looking at the Statistics window in Xojo). After a restart, this comes back down to about 20%, and then it slowly creeps back up in time

This got me thinking if things are not getting destroyed after use/user logs out. I have self.Quit in the Session.UserDisconnected, which I thought would destroy anything that’s no longer being used

I have a bunch of Session properties, but I also have some WebPages with a lot of properties too. I know properties are best declared and used in code so they are destroyed after use, but is there any problem with having a lot of properties on a page, or should I try to minimize these and move to Session properties if possible? The properties are nothing crazy: strings, integers, doubles, and arrays, some pictures

What you’re describing is called a “memory leak” that is, a block of memory that’s not referred to by any accessible blocks in your code.

Firstly, the intrinsic types like String, Integer, Boolean, Double, etc are immune to this issue, but other types which are made from classes are not.

The thing you need to watch out for is what’s called a “circular reference.” That’s caused by one object holding a reference to another object and whether directly or indirectly the other object holding a reference to the first one. A good example of this would be if you had added a property to WebPage1 called MySession as Session which was set to the current session when the page was created. The trick is that Sessions themselves also contain an array of the currently allocated Intrinsic WebPage instances. Since the Xojo framework uses reference counting, an object cannot be truly destroyed until the very last reference to that object is released. In the example I gave above:

  1. The Session holds a reference to WebPage1 (in the array)
  2. WebPage1 holds a reference to the session

Now, when the user leaves and you call session.Quit, the framework removes the instance of the Session from the App class (which keeps an array of all active sessions) but that is only one of the two references, the other is the WebPage property, so the session won’t be destroyed. WebPage1 will also not be destroyed because the Session still has an instance in its array.

We did an exhaustive search of the web framework when version 2 was released in 2020, so I’m 99% sure that it’s not the framework causing this unless some new issue has been introduced.

Thanks for the information Greg. I’ve read several of your posts on circular references. It is a confusing topic. I don’t think I have any WebPages having a property as Session. I also don’t think I have any specially-created classes. I will have to recheck things to be sure. The project is basically made up solely of WebPages, containers, dialog boxes, and now also WebToolbars

Would any of these be a potential culprit?

  • A Session property myColor1 as Color, for example. This is called on many pages to alter the colors of buttons and such. Users have the ability to choose a color scheme. There’s plenty of other Session properties, but these are booleans, strings, arrays, integers, doubles, picture, WebFile, and databases (MySQLCommunityServer and SQLiteDatabase), so it doesn’t sound like these should be problematic
  • A WebPage that has a container control nested inside a PagePanel (ccMyContainer1 as ccMyContainer). Curious if things like this get kept in memory and are never destroyed even when navigating to a different page

A property of type color is just an integer, so no to that.

WebFile could be. I don’t remember the internals of WebFile, but they do refer to their session so that two users could have a file named “my passwords.txt” and not accidentally download the wrong one. It’s probably just the identifier, but @Ricardo_Cruz would need to tell us one way or the other.

The answer is “it depends”. If the page in this case is marked as intrinsic, it and all of the things placed on it will exist as long as the session exist unless you called the Close method on it.

Also, I’ve seen a lot of devs create properties on their containers to make it easier to reference the parent WebPage. That’s also considered a circular reference unless you use a WeakRef to hold it. The WeakRef thing is easy to do with a computed property and can fix weird stuff like this

Essentially, instead of having

Public ParentPage as WebPage

You’d have

Private mParentPage as WeakRef

And a computed property

Public ParentPage as WebPage
Get
  If mParentPage = Nil or mParentPage.Value = Nil then
    Return Nil
  End if
  Return WebPage(mParentPage.Value)

Set
  MParentPage = New WeakRef(value)

You just need to make sure you check the result for nil or wrap in a try-catch for a NilObjectException.

1 Like

I do this for sure. I will have to work on this next week and see if that makes any difference. I haven’t been making any use of WeakRef, but I may need to incorporate this too

Thanks for the help!

Yes, you’re right. WebFile just stores the WebSession.Identifier as String internally. Then WebFile.Session Computed Property uses it to return the Session instance on the fly.

@Ryan_Hartz A simple test to see if your WebPage instances are being cleaned up is to add the Destructor method and do some logging. If you use macOS, you can check the memory allocations using Instruments, and see what could be causing these memory leaks.

If you happen to encounter one caused by the Web Framework itself, please create a new Issue, so we can fix it in the next available release. @Jeremie_L has found some during these years.

Do you use URLConnection in your web app?

I have discovered a pretty big memory leak in my app because of URLConnection.
I need to restart my app every month like you.
But in November and December each year, when my app has several thousand connections per day, I need to restart the app every 48hrs.

https://tracker.xojo.com/xojoinc/xojo/-/issues/78053

Feel free to PM me if you need help finding possible memory leaks in your code.

2 Likes

I just started playing around with this, so will do some additional testing (never used before so am learning how to use Destructor to monitor)

None at this time in my web apps, but this is good to know for future reference!

Since Greg’s post the other day, I went through my project and made some changes. I have a memory report feature added to the project (I think this was contributed by @Jeremie_L ), which shows the current amount of memory the app is using, the number of sessions (current, closed, and total), and various details

First, I have been making use of containers on my pages, mostly to simplify things, and there might’ve been some circular reference as Greg pointed out. I got rid of these and just added the controls/properties/methods right to the pages where they go. Published the app. There was still several users getting kicked out pretty frequently

I then remembered another feature I recently added and wondered if that could be problematic. I disabled these, and the kick-outs were greatly improved. But I did notice yesterday evening there were several users who had to re-login all around the same time

This brought up another question. I think I have identified the page that is causing issues, since it is the most widely used page by my users and the one those who contact me say they were in the middle of using when they got logged out. So my question is, if there is something on the page that causes a crash, maybe it’s a NilObject or something not specific to a memory leak, would one user’s app crash make the whole app have to restart for all users? I thought of this when reviewing the MemoryReport. Before I shut down yesterday, the memory was around 60MB, and the total users (current and closed) was around 100. Right after I noticed users had to re-log in last night, I checked the report, and it looks as though the app completely restarted. The memory dropped to 12MB, and the total users was 1.

Should I be focusing on looking for something that is causing a crash, making the app have to restart for all users? Or does one user’s app crash affect only their Session and not the whole app for all users?

It depends on a few things.
If you are returning True from the various UnhandledException events, the whole app shouldn’t crash.

You could implement Sentry in your project to report exceptions if you aren’t using it yet.

The free tier of Sentry is quite high, it took me one year of using it before upgrading to their paid tier.

2 Likes

I am using Sentry in some of my mobile apps. Maybe I’ll have to implement it with the web app too

Another tool I use to monitor my app is the Pushover API

My webapp sends me a notification directly on my phone each time the app is started.

Two lines of code in the app opening event are enough for that:

Var conn as new URLConnection 
conn.Send("POST", "https://url_to_pushover_api")
3 Likes

To add another resource, I’ve added public status monitoring display using HetrixTools - Uptime Monitor. It’s free for 15 monitors and has saved me some headaches. I know practically immediately when something goes wrong, which has been useful with a recent issue we’ve been trying to track down where my demo app would go unresponsive but not exit then restart.

2 Likes

Another one to add to this list is StatusCake. Three monitors for free and they’ve saved my bacon more than once, as recently as yesterday.