First of all, while somewhat correct, your initial claim is not entirely true. You are right in saying that just getting rid of all references to the table will not free up the memory used by its elements. Not right away, anyway. They will eventually all be garbage collected.
So What's Happening?
The garbage collector will collect the table during a first pass, and then its elements on a second pass.
On the first pass the garbage collector doesn't know that the elements no longer have a valid reference. Or rather, it believes there is still a reference to them; the table. Once the table has been collected, the elements become eligible for garbage collection also, but this will not happen until a second pass of the garbage collector.
On Garbage collection
Another thing I'd like to clear up that most people don't know about garbage collection is that objects subject to garbage collection (that is, tables, userdata, functions, threads, strings, etc.) become eligible for collection as soon as there are no valid references to them, but, and this is the important part, the actual garbage collection is not guaranteed to occur immediately when the last reference to these objects ceases to exist. Lua only guarantees that the actual garbage collection may happen at any time following the loss of the last reference to the object. It is possible to trigger a garbage collection manually through collectgarbage("collect") (though this feature is disabled in Roblox both for performance and security reasons), but Lua could decide to trigger a garbage collection at any point during your code's execution because it deems it is running out of memory, for example.
From Lua's documentation:
"Lua manages memory automatically by running a garbage collector from time to time to collect all dead objects [...] Lua implements an incremental mark-and-sweep collector."
The latter means that the collection proceeds in small steps that are interleaved with normal computations; i.e, your code's execution.
About Weak Tables
Otherwise, yes, a table with weak values would not count towards the elements' reference count, and so the elements could theoretically be garbage collected along with the table:
"A weak table is a table whose elements are weak references. A weak reference is ignored by the garbage collector. In other words, if the only references to an object are weak references, then the garbage collector will collect this object"
If either the key or the value of an element has no other references then the key-value pair will be removed from the table, and the corresponding key or value garbage collected. But as your code is right now, your elements would become eligible for garbage collection immediately after creation, as they have no other reference besides the table.
However...
What can cause garbage collection problems is tables with indirect circular references.
That is, table #1 contains a reference to table #2, which itself contains a reference back to table #1. This kind of structure confuses the garbage collector, as it sees both tables as still having a reference, and for this reason neither tables will ever be garbage collected, resulting in a dead-lock. This can -- and will -- result in memory leaks.
This issue has been addressed in later version of Lua.
3 comments
Thanks for clearing that up! I'll leave a comment on here or I'll be sure to contact you on discord or something if I have any more questions concerning this.
I'd be happy to answer any and all questions you may have. :)
A very good Q/A! I can clearly feel same professionalism feeling that a stack overflow Q/A would.