Potential Character (Event Connect) Memory Leak

When a character is added, I connect this function to the character:

character.ChildAdded:Connect(function(child)
	table.insert(childs,child)
end)

This way, I will always get all descendants of that charter that are added, since the load is sloppy and I want to act ASAP with the parts in contrast.

My concern is that this connect may never get garbage-clean-upped. I mean by default I’d assume yes, the model is probably destroyed. But then again you can encounter wacky stuff, like the pointer to the character being wrong, as if you do character = player.Character it will refer to the no longer in use model in nil, for some reason still existing. If this is a problem, how am I to counter it? (disconnecting when?)

The connection will get disconnected when the character is destroyed, however what will cause a memory leak is if you do no remove the character’s children that is store in the “childs” table when the character is destroyed, this will prevent the children from being GC’ed since your holding a reference to them in the array, however this depends on the location of the script, if this script is in startercharacterscripts, which gets destroyed when the character does then its fine, however, if its not you need to remove the references when the character dies.

This solution is not the best since it will not work if the death state of the humanoid is disabled a more concrete approach would be this:

Character.AncestryChanged:Connect(function(_,NewParent)
    if (NewParent == nil) then  
        --the character is destroyed
    end
end)

Also it does not matter if he uses a dictionary or array it just important that the references are removed.

1 Like

You can set the tables __mode to “v” if you don’t want table entries to hinder GC.
local childs = setmetatable({}, {__mode = "v"})

The developer hub says that the __mode metamethod will never hold weak references to roblox instances, Metatables | Documentation - Roblox Creator Hub

I recommend not trusting the hub regarding metamethods, since they’re wrong or missing details. Roblox instance references are indeed weak in a weak table. They usually don’t get GCed since they’re parented to game. The hub fails to mention that the instance will get GCed if the instance was destroyed and if the reference is weak.

In the following example the reference is cleaned up while the instance itself isn’t since it is still a descendant of game. Destroying the instance after the table insertion is necessary for full GC (table must have mt.__mode = “v” or the instance will remain in “nil”).

local weakTable = setmetatable({},{__mode = "v"})
table.insert(weakTable, workspace.Part)
--workspace.Part:Destroy()
wait(1)
print(next(weakTable)) --prints nil; if __mode wasnt set, it would have printed the instance

Whether this is intended or not isn’t the question here, but my initial answer correctly reflects how Luau works as of right now.

1 Like

I would still recommend manually removing the references, imo.