How to get rid of a Dictionary as fast and efficient as possible?

I have a situation where some complex structure is built (in the background) and it’s result is represented in a Dictionary. The Dictionary then contains other Dictionaries and a lot of instantiated objects. That Dictionary is being used in the GUI to show it’s containing data.
So far, so good :slight_smile:

I’ve then noticed that as soon as I no longer need that populated Dictionary, the application gets into a “not responding / spinning wheel” state for > 10 seconds (depending on the size of the Dictionary).
The cause of this is simply trying to get rid of the Dictionary.
So this happens in situations like:

  • ContainerControl.Close or ModalDialog.Close (where this dictionary is used)
  • theDictionary.Clear
  • but even when for example “refreshing / reloading” data, and doing a theDictionary = nil or theDictionary = New Dictionary
  • of course also when closing the application

It seems that it’s related to the way the Xojo Framework does it’s “reference counting / garbage collection / memory-cleaning-up”.
And I wonder… what does the Framework take soooo long to “clean up”? Is it so expensive to get rid of a couple of thousand objects (stored within the Dictionary)?
A more important question though: How can this be done more quickly? How can I just “get rid of the Dictionary (and all it contains)” immediately (without having to wait for 1-10 seconds)?

If I assign the Dictionary to some other (global) temporary Property before setting it to nil, then I get the desired effect (within the “Control” where I want to continue without delay). But then it’ll happen the second time (when the first instance that is now in the temp-Property goes “out of scope”).
I certainly can’t just keep all ever instantiated ones in Memory :wink:
And even if these “no longer needed Dictionaries” get temporarily referenced in some other way, I would need to “clean them up” some time later - that’s just deferring the “wait” to some other (unexpected) time.

So - any other ideas?
Here is a quickly mocked up example project you can play with if you’d like to do so…

  1. Click ‘Build Dictionary’ (and wait a while to build the Data Structure)
  2. Click ‘aDictionary = nil’ (and it’ll take a couple of seconds to set the Property to nil)

That’s kind of bizarre. I tried putting the methods into a thread and at least it didn’t lock the app though I think the wait cursor popped up a few times. This says that maybe there is something that happens in the Destructor that’s blocking the main thread?

That’s what I meant/feared with the idea/approach to create some other (delayed) way of setting the reference to nil (e.g. by storing it in some temporary array, that occasionally is being emptied). It might just “lock up the application” at some other point in time. And an own “scheduler” also can’t know when it’s convenient to do so…
It’s certainly a kind of situation that can easily occur. And it happens most often when “closing (a control / window / application)”. Or when “refreshing (new data - get rid of old data)”. And I don’t see any reason why this would take (multiple) seconds to free memory/references…

But nothing that we can change in own code, right? In seems to be in the Destructor’s of the Xojo Framework?

Idea: override Clear so the Dictionary first gets flattened out into a Variant array, clears itself, then starts a Timer that sets each element of the array to nil. The Timer will exit after, say, 3 ms and resume on its next iteration.

wouldn’t this do the same thing

theDictionary = new dictionary
// or even
theDictionary = nil

First I tried to have a global Module with a global Array. Then fire a Timer that will start a Thread that ReDims that Array (to get rid of all it contains).
While the “GUI Method” returns quickly, one still notices a “locking up”, e.g. by moving the Window with the mouse.

So getting rid of “all at once” doesn’t seem to be working in a “good way” :frowning:
Thanks for this idea - I’ve quickly implemented that in the example project (now with a “modDestroy”). It now calls theDictionary.Destroy before setting it to nil (or letting an instance go out of scope). The Dictionaries Values are appended to some global array, and a Timer will remove one-after-another.
That seems a possible way to at least not visibly lock up the UI. But it’ll take a while for the Timer to do the “manually coded slow cleanup” :wink: Immediately quitting the application after setting to nil is still “slow”.
But really… what is so expensive to get rid of a couple of thousand objects…?
At least this “Timer that removes one-value-after-another” idea is some (hacky - in my opinion) way to at least have a decent UI behavior in such a situation. But shouldn’t the Xojo Framework handle this in a better way? I still can’t quite believe that just setting a Property to NIL may cause an application to lock up for several seconds…

[quote=450466:@Dave S]wouldn’t this do the same thing

theDictionary = new dictionary // or even theDictionary = nil [/quote]
You might not be understanding what the problem is. Download the test project to get a better idea.

The issue here is that as soon as theDictionary has a reference count of 0 (by setting it to NIL or by replacing the Property with a new instance), Xojo’s “memory/garbage collection” kicks right in (even in the MainThread!). And freeing up all those Object-Instanced in the “no longer needed/referenced Dictionary” takes such an awful long time… in a place/situation where you don’t want it to “lock up”.

Yup - @Dave S try and see yourself. The link and original situation is in the first post.

Why do you use a dictionary instead of an in-memory database?

This is a test situation. The idea here is to push things to the limit in a simple project to show the problem.

Not everything you get in your hands you have designed yourself :wink:

And yes - I’m trying to figure out how the Xojo Framework can be used to handle this best… it’s an effect that can occur in many situations, slowing down code in a place you probably don’t expect it to be slow.
Or do you expect setting a Property to NIL could cause a delay of several seconds? Okay - it’s a Property that holds some “structure”. But still…

I am trying something similar but entirely within the a Dictionary subclass’ Destructor. I’ll post when I have something practical.

Thanks :slight_smile:
Dictionary is not the only one. It‘ll probably be the same with an Array (that holds 1000s of Class-Instances) and others (custom/own classes and constructs)… it‘s just where I have found such a situation.
I‘m also looking at this in a more global way.
How to get the XojoFramework clean up memory without blocking the MainThread, possibly locking up the application?

I‘ll be offline some hours, so thanks again in advance :wink:

Thread the removal of the entries?

Oh, now you tell me.

Cant be sure because you cant see the goings on of the innards of the framework but I’d suspect that by niling the dictionary that doing so causes it to then have to check all its object members to see if they can be destroyed and then each of those and so on down through the dictionary of dictionaries

So you suffer the penalty of a giant recursive call to destroy the dictionary

Depending on what this is supposed to represent I might suggest other alternatives
In memory databases are immensely handy, very fast, and can be cleared extremely quickly
A different structure other than a dictionary may work very rapidly

I put my concept here:

https://www.dropbox.com/s/2ewexa3gklrsh5z/DictionaryTest%20-%20Kem.xojo_binary_project?dl=0

In short, it’s a Dictionary subclass that, upon destruction, will hold a reference to itself, then start a low-priority thread to walk through its contents and get rid of each item. When done, it removes the circular reference and raises an event.

This is aware of arrays and will dive into them too, but that’s not tested in your example, it seems.

Destruction takes 15-20s, but does not interfere with the UI and does not delay quitting.

This is almost funny in that it works around reference counting and how it behaves to implement a garbage collection system :stuck_out_tongue:

A summary to mark as answer…
The situation is: If a Dictionary contains a lot of objects, then setting it to nil (reference count = 0) will immediately cause it’s destruction. If a lot of object are contained, this might take a couple of seconds - possibly “freezing” the app / MainThread.[quote=450485:@Norman Palardy]that by niling the dictionary that doing so causes it to then have to check all its object members to see if they can be destroyed and then each of those and so on down through the dictionary of dictionaries
So you suffer the penalty of a giant recursive call to destroy the dictionary[/quote]
So basically the “Reference Counting” system is playing against a good UI experience here.
A workaround is to make yet another reference (so that it still stays alive), and work our a mechanism to “slowly destruct” it in the background (leaving the UI and MainThread responsive).

Thanks a lot to @Kem Tekinay for his idea - and to show this in an example project!

[quote=450486:@Kem Tekinay]I put my concept here:

In short, it’s a Dictionary subclass that, upon destruction, will hold a reference to itself, then start a low-priority thread to walk through its contents and get rid of each item. When done, it removes the circular reference and raises an event.
This is aware of arrays and will dive into them too, but that’s not tested in your example, it seems.
Destruction takes 15-20s, but does not interfere with the UI and does not delay quitting.[/quote]
This idea/concept can also be applied to other objects. If you have some “structure” put collected all together in a “main/parent object”, it’s a good idea to check if removing it’s last reference will cause a noticeable delay. If so, such an approach can help.

Thanks again! I hope you’ve also had a bit of fun exploring this situation :wink:
And I just have to write it once again: I love this forum and community :slight_smile:

I’ll look into your “proof of concept” in more detail the next couple of days, and I’m curious to see if I can make that approach work in our products’ situation(s). If so, there will be many thankful customers of ours that get less “spinning wheels” to see while working with it.

I’m still not quite sure if the Xojo Framework couldn’t handle this better (e.g. by doing it’s destruction work always in the background - and again: seconds… for that tiny amount of data/memory…)… what do you think? Would that be worth a feature request, or would that make things in the Frameork more “fuzzy”, so that it’s not a good idea to place in Feedback?

Anyway - I think this kind of situation one can run easily into… and while it’s kind of “logic”, it’s also quite unexpected.
@Kem Tekinay - I think this would make a good (guest) post/blog, or even an article for Xdev :wink:

I’m always interested to read about these kind of “performance tricks” - such as the one with the difference between referring to a Control by Name (slower) or by Property (faster).