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

It shouldn’t be hard to create a generalized “garbage collection” module that uses variants and Introspection to dissect and remove objects through a thread. Perhaps I’ll turn that into an open-source project.

On further reflection, such a generalized system would be dangerous because there is no convenient way to get a reference count. In fact, even the code I wrote should be used with extreme care.

To illustrate:

dim d1 as new Dictionary
d1.Value( "internal dict" ) = new Dictionary

dim d2 as new DictionaryWithDelayedDestructor
d2.Value( "my dict" ) = d1

d2 = nil // d1 will be wrecked

To avoid this, the reference count of every object that is going to be destroyed has to be checked before processing that object. If the reference count is greater than 1, it should be left alone. Unfortunately, I don’t see a way to extract that information from Xojo.

In short, my solution works but is impractical, and even dangerous, for general use.

I put in a feature request for the ability to get reference counts.

<https://xojo.com/issue/57003>

I’ve noticed that when I tried to just add your Subclass and use it instead :slight_smile:
This resulted in unexpected NilObjectExceptions - most likely due to “context switches” causing Paint-Events (which make use of these Dictionaries) to fire in an unexpected time.

I still like the general idea. And I guess I’ll have to use it somehow.
Most likely something along these lines (see updated example project):

  • (manually) append all .Values to some temporary Array (to increase the ReferenceCount of these)
  • this then allows the Dictionary to be .Clear-ed and =nil-ed much faster (since that doesn’t immediately cause it’s values to be Destructed right then)

In this first updated example, check [x] Dispose of Values first to see how I think it would work (at least for our situation). The temporary “disposal Array” is currently being emptied via Timer, and I’ve played a bit with “batch sizes” (it’s not best yet… I don’t want it to take too long, but big batches still cause some “hickups” e.g. during moving the Window while “cleaning up”) - maybe that would be better using a Thread?

I think with this approach, this should be given… as long as one only requests theDictionary.DisposeOfValues(true) only when being sure it’s no longer being used (and right before .Clear or =nil).
It doesn’t mangle with the “original dictionary’s values” (so the “original” reference count of the .Values will remain - it’ll only be increased by one while being added in the temporary disposal array - to help the Dictionary itself being able to be “Destructed” immediately and fast, and not block the current “MainThread / run loop”).

Hmm… back to your example.
What if you comment out two lines in your example?
In Method AppendToTree: don’t do 'objArr( i ) = nil and don’t do 'd.Remove k

This would leave the Dictionaries (and other referenced Dictionaries) “as they are” - no harm done.
But it will append the “to be destructed Dictionary’s” Values (and sub-sub values) to some Array, therefore increasing their ReferenceCount. And as a result allowing to have the Dictionary be slowly and delayed destructed (since your cleanup mechanism will do the “Garbage Collection” in the Thread) - and not blocking the current “run loop” (when setting such a Dictionary to nil).

Would that be less dangerous? Your illustration code snippled would then work “as expected”.
Then a similar way could be added in your subclass for .Clear. That’s still slow. My approach in the post just above would allow .Clear to be “fast”, too.

I think some combination of the two ideas/approaches could result in something useful and “not dangerous”…
I like your “self contained” way with the Subclass. It’s just that in our case this would cause hundreds of Threads to be running… so maybe a combination with a “single/global” disposal would work best.