__mode metamethod not working as expected

Hello! I hope you are feeling well today! I have noticed that __mode is not behaving as expected. I don’t know what’s going with it.
Anyways when you use any sort of yield, and the yield last for more than 5 seconds it will glitch __mode behavior. Is this expected?


With Yield Example: (Adding a wait 10 at the top)

wait(10)
print("Running!")
local Object = {}
--------------------------------------------------
local WeakTable = setmetatable({}, {__mode = "v"})
WeakTable[1] = Object
Object = nil
--------------------------------------------------
repeat task.wait(1) until WeakTable[1] == nil
print("The object got garbage collected!")

Output:

--> After 10 seconds it will print 'Running', but not 'The object got garbage collected!'.
Running!

Without Yield Example: (Removing the wait 10 at the top)

--> wait(10)
print("Running!")
local Object = {}
--------------------------------------------------
local WeakTable = setmetatable({}, {__mode = "v"})
WeakTable[1] = Object
Object = nil
--------------------------------------------------
repeat task.wait(1) until WeakTable[1] == nil
print("The object got garbage collected!")

Output:

--> After 10 seconds it will print 'Running' and 'The object got garbage collected!'.
Running!
The object got garbage collected!
2 Likes

I was having a similar issue with this a few days ago. When I went into a live game, it functioned normally. In Studio, the problem only occurred on the server. (But if the delay was small enough, it also worked normally.)

1 Like

I was just dealing with this problem today. Here’s my interpretation: in order for an object with a weak reference to be garbage collected, the garbage collector must run in the first place. If there aren’t any scripts actively doing anything, and memory usage is good, then there’s no reason for the garbage collector to run. This is likely what is happening.

I’ve found that adding the following line somewhere will keep things active and cause the garbage collector to run more often:

game:GetService("RunService"):BindToRenderStep("",0,function()end)

Remember that this is just for debugging; it isn’t required for weak references to work correctly, as they are already working just fine.

4 Likes

You can also force garbage collection by running this:

collectgarbage(“collect”) although maybe you have to pass in a different arg, like “count” iirc.

Don’t do this in production, you want Roblox to manage it for you.

Doesn’t Roblox disable all collectgarbage arguments except count anyway? I do believe there’s also gcinfo() as a shorthand for collectgarbage(“count”).

Unfortunately, collectgarbage hasn’t allowed any argument except “count” for over a decade, and neither “count” nor gcinfo actually causes the GC to run, either.

1 Like