Weak References Help

I have been researching how to use weak references using the metafield: __mode . I have produced examples based on my research, but it behaves in a different way than I expect. Attached is my code and output from running it. Initially, I create a root table with weak values and two other regular tables. I set the first and second index to the two other tables respectively and then set one of the strong table references to nil. I yield for 1 second which is plenty of time for multiple GC jobs to happen, but the weak reference to the table whose strong reference was nil-ed still exists. I would expect it to be removed and cleaned up. I am running this code on a script that runs at server runtime in studio.

image
image

Expected Output:

{
  [1] = {
    [1] = 2
  }
}

As extra, I modified my code like this:
image

And saw multiple “GC” labels in the microprofiler after the “FIRST” label and before the “SECOND” label was reached. What is happening here?

https://gyazo.com/20bf689db050cef3e9eca52ee6d6120e

From my experience, with nil values, and Lua, nil values end up remaining in data. Instead of setting data to nil, I use table.remove by referencing the key value of the record - I don’t trust using nil, anymore.

Examples I see online, are functions that iterate thru the array and reset the array, minus the record set to nil.

The value gets gc-ed properly for me


The second print printed index 1 as void

I ran the same code on the client in studio and got this result. Very strange inconsistent behavior!
image

I actually yielded for 5 seconds though instead of 1 second, which is even more plenty of time for a GC job to occur.

Here are some of the tests I ran trying to figure out what is happening:

Loop Running Code on Client

image

Loop Running Code on Server

image

Loop Running Code on Client (with large tables)

image
image

Loop Running Code on Server (with large tables)

image
image

Possible Conclusion

Based on my tests, I think it would be fair to say script data such as shown in the examples will only get GCed after a certain amount of data to be GCed is went above. If anyone knows any more technical details on this feel free to share!

Marking a table as weak does not make any guarantees as to when the referenced data in the table is garbage-collected.

It’s entirely up to the garbage collector itself, and it, as you noticed, only seems to collect these weak references when a threshold is met.

There’s a pretty simple assumption that can be made off of your findings, which is that the garbage collector puts off cleaning up references until necessary to facilitate fewer and shorter pauses in the runtime of your program.

Long story short, if it doesn’t absolutely need to clean it up, it won’t.


You very well may have come across this in your travels, but in case you haven’t, weak mode has no affect on Instances; a reference to an Instance is always strong.