The incapability of the "__mode" metamethod to check for memory safety relating to garbage collection

tl;dr: I can’t tell if garbage collection is working or not, as I believe it doesn’t run at all in some cases

Hello fellow developers. For the past week or so I’ve been trying to script with memory safety in mind. Unfortunately, my development has come to a complete halt as I cannot figure out if what I’m doing actually makes sense.

For context, I’m developing a ranged weapon system and I want it’s logic to be implemented solely under ReplicatedStorage and ServerScriptService. I find the idea of copying the same script a bit icky. To make sure my weapons don’t get initialized multiple times, I have to record these instances somehow.

Now, you may ask, “Why don’t you just use AncestryChanged?” Because there’s the possibility of the weapons being parented to nil, then parented back under the DataModel later again. (If your game has an admin system on it, the ;refresh command will do exactly that.) .Destroying is still in development so that’s unreliable.

That leaves me with no choice but to record these weapon instances in a table with it’s __mode metamethod set to "k".

local initializedTools = setmetatable({}, { __mode = "k" }) -- weak keys

I still have no idea if this works, when I decided to use a debugger later on to check, I still found them visible in the Watch window. I checked to see if my code just sucks, I got it down to the most bare-bones version I could get, shown below:

local initializedTools : {[Instance] : boolean} = setmetatable({}, { __mode = "k" }) -- weak keys

initializedTools[Instance.new("Part")] = true

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

while task.wait(10) do
	for i,_ in initializedTools do
		print(i)
		i:Destroy()
	end
	task.wait(5)
	print("bump") -- ! inserted a breakpoint here !
end

I don’t know what to make of this, either garbage collection just doesn’t work, or my place is so efficient that garbage collection never runs a cycle during testing. I can’t force a garbage collection cycle either, Roblox does not provide any way to do that.

Note: Strangely enough, the only time I see this table actually get cleared is when I run ;re with Adonis admin commands while I have the tools listed in the metatable. Maybe there’s something complex there that “wakes” it up? I don’t know.

Edit: I have tested by taking weapons, dying, then taking weapons again, then dying again, to see if it would have any changes on the table over time. After several restarts it never got past a certain amount of instances. Maybe my intuition is right and garbage collection just runs whenever it feels the time is right. Still such a bummer that I can’t explicitly call it to clear that up. It would make testing a LOT easier.

Garbage collection in weak tables only happen when more memory is being allocated; in other words, the objects in your weak table will only remain there until more memory is portioned out. If you really want to test this, you could make a loop that just generates an abundance of other parts (parts consume memory)

I use weak tables somewhat often as backups, but in your situation i’d just try toying with .Destroyed or continue using weak tables

2 Likes

Garbage collection on Roblox generally runs when memory load occurs.
For example, when there are a lot of objects (Instances), the garbage collection cycle will actually do a full cleanup of the objects that are no longer referenced and destroyed within your code.

To manually trigger this, you need to create a load. You can achieve this by creating a large number of instances simultaneously and then destroying them later.

2 Likes

I see, it’s quite a bummer there is no simple way to check memory safety without using such tricks. Last time I checked, .Destroying didn’t even fire when objects fell into void. I really cannot trust those.

1 Like

Yeah it sucks. Make sure that the objects in your weak table don’t have references either, like @TheRealANDRO said. If you still have references in other part of your code it won’t be GC’d.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.