Date / DateTime and memory usage

I’ve been having problems with memory leaking when using Date and DateTime functions.

This seems to show that the memory is cleaned up after usage, but I’m still getting a memory leak whenever I use a Date or DateTime object.
https://tracker.xojo.com/xojoinc/xojo/-/issues/67558

We develop several server applications which have threads running in loops scheduling various operations. Essentially, these threads never end, but sleep between loops.


dim d as new date
while true
  while me.logs.LastIndex>-1
    dim y as integer = d.year
    system.DebugLog("L" +str(Runtime.MemoryUsed)+" "+str(y)+" "+me.logs(0))
   me.logs.remove(0)
    me.Sleep(10)
  wend
  me.Sleep(100)
wend

This leaks every call to d.year (DateTime is the same as are any other date property). The memory is never cleared up. If I remove the while true then when the thread finishes, the memory is released properly.

I’ve re-factored the logging thread to be run and finish properly, but there are others that really don’t want to be done like that. I would have to add another timer to do the schedule which launches the thread which adds extra complexity and confuses the class structure as various scheduling functions now have to have a timer and thread.

Does anyone have any suggestions?

Regards,

Lee

Note, on the example above that there is only ever 1 date object, but many references

What Xojo version and OS? I do remember something about a bug in Xojo memory management in loops under macOS (not sure if it affected others, but it was detected on macOS), something like postponing clean up after the loop, and a huge loop was blowing things up.

Xojo 2023r4 MacOS. I’ve just tried it on Windows 11 and it was ok

This shouldn’t be inside the loop anyway. It’s never going to change.

Don’t do that.
The underlaying macOS objects are not freed until the loop ends.
Sleep() may not help there.

You can use NSAutoreleasePoolMBS class to manually collect the objects and delete them.

1 Like

Well, yes. This is an example. It’s just to show that references the date object causes the leak

I’m now refactoring the threads in the service application into timers with the action event doing the work. This has brought back a problem I had years ago where if the action inside a timer event takes longer than it’s period then all the timing going completely wrong. This is literally why I stopped doing things in timers and moved everything to threads. Some things in the code can take several minutes to complete. I had to add a timermode=0 at the beginning of the action event and timermode=2 at the end to get around it.

An integer should be a copy, and released at each loop cycle. The only penalty should be speed.

I think that William corrected this bug in some way, because he said he fixed it.

Have a look at https://documentation.xojo.com/api/language/timer.html#timer-timercalllater. I use this to repeat processes after a specified period of time.

How do I use NSAutoreleasePoolMBS?

I added a pool property to the thread and

#if TargetMacOS
pool = new NSAutoreleasePoolMBS
#endif

at the beginning of the run event, but the app just quits. There’s no error generated as far as I can see.

I can have up to 5 independent instances of the thread running. I’ve refactored most of the threads I have so that they run once and are started using a timer, but this one I don’t want to work like that. The thread is there to monitor job changes and update in the background. I don’t want any of that code to interrupt the main UI as it’s quite sql heavy.

Regards,

Lee

My small test program with 5 threads, each with their own pool and new NSAutoreleasePoolMBS code works fine. No memory leak and no quitting, so there must be something else going on.

However, removing pool = new NSAutoreleasePoolMBS from my main code definitely stops any crash. app.cancelclose is never called, so ‘quit’ is not being called properly.

I have to do the Autoreleasepools for a couple of things. I let them run every 50 to100 iteration like this:

dim AutoReleasePool as new NSAutoreleasePoolMBS

if MailCountForAppleScript mod 50 = 0 then
  AutoReleasePool = nil
  AutoReleasePool = new NSAutoreleasePoolMBS
  DelayMBS 0.1
end if

The code is so old that looking at I’m not even sure that it makes sense. But it works.

I’m not sure how that code would run in a thread, unless it’s done once every 50 loops, for instance.

This doesn’t leak (in my test program) and doesn’t crash either.

me.pool = new NSAutoreleasePoolMBS

dim d as new date
while true
  me.Sleep(1000)
  dim y as integer = d.year 
wend

Commenting out me.pool causes a leak, as presumably the date object memory is never cleared up. My main app has many threads which are created and finished with as various background jobs are opened and closed. i.e. remember the last 5 job data. When a new one is added, remove the oldest one.

I tried this, but it just crashed when pool count got to 50 and NSAutoreleasePoolMBS was run

#if TargetMacOS
  if poolcount = 50 then 
    me.pool = nil
    pool = new NSAutoreleasePoolMBS
    poolcount=0
  else
    poolcount = poolcount+1
  end if
#endif

Making ‘pool’ a local properly of the run event is looking promising. I’ll run this for a few hours and see how it goes.

dim pool as NSAutoreleasePoolMBS
dim poolount as integer
while true
#if TargetMacOS
  if poolcount = 50 then 
    pool = nil
    pool = new NSAutoreleasePoolMBS
    poolcount=0
  else
    poolcount = poolcount+1
  end if
#endif
//do real work etc....
me.sleep(1000)
wend