PSA: Connections can memory leak Instances!


#41

What would be better?


#42

The first one still leaks memory (Probably… if the Player object is Destroy’ed then neither would leak but I don’t think it is). You actually have to disconnect the reference to the connection that you save in the table, just saving the reference to it alone doesn’t accomplish anything:

for name, connection in pairs(playerStuffTable[plr]) do
    connection:disconnect()
end
playerStuffTable[plr] = nil

The second version will work since the Destroy disconnects the connection.

A better way to accomplish the same thing would be to put all of the stats inside of a “Stats” Folder and just Destroy the whole Folder so you don’t have to loop over each individual stat.


Memory Leak Issue
#43

For a function like this which is just in a main game script and can never be disconnected,

image

,would I have to dispose of the “plr” and “itemName” variables somehow? Or is only the connection to the CraftedItem event what matters?


#44

As long as the two arguments aren’t being stored elsewhere they should be GC’d automatically (plr, itemName). So for your question, yes only the event matters because it has a reference and is connected to be listened too.


#45

I require clarification on this. I still destroy my top-level object so in essence everything below is fine, but this gears more towards permanent scripts.

  • Assign table to variable “Tweens” in a do-end block
  • Insert Tweens into those tables via table.insert
  • Call Destroy on the Tween once it fires Tween.Completed

I called destroy on the tween, but I print #Tweens and it still reads 3. Are these hanging references that I need to dispose of or will the do-end block take care of that for me?


#46

This depends on if your Tweens table is inside or outside of the do end block and if Tweens gets referred to by any other part of the script.

This, for example, is fine, but Tween will only be garbage-collected up once the outer do end block is done:

do
	local Tweens = {}

	do
		local Tween = MakeTween()
		table.insert(Tweens, Tween)
		Tween.Completed:Connect(function()
			Tween:Destroy()
		end)
	end  -- `Tween` loses one of its references, the `Tween` variable, but it still has another in the `Tweens` table, so it is not garbage-collected
end  -- `Tweens` loses its only reference, so it is garbage-collected, so it no longer holds any reference to `Tween`, so `Tween` loses its only reference, so it is garbage-collected

If you want Tween garbage-collected before that (for example, when the tween is completed), then you need to manually remove the reference from inside the Tweens table:

do
	local Tweens = {}

	do
		local Tween = MakeTween()
		table.insert(Tweens, Tween)
		Tween.Completed:Connect(function()
			Tween:Destroy()
			for Index, Value in next, Tweens do
				if Value == Tween then
					table.remove(Tweens, Index)  -- remove reference inside `Tweens`
					break
				end
			end
		end)
	end
end

Or, alternatively, you could use a dictionary. This is easier and perfect for this use case:

do
	local Tweens = {}

	do
		local Tween = MakeTween()
		Tweens[Tween] = true
		Tween.Completed:Connect(function()
			Tween:Destroy()
			Tweens[Tween] = nil
		end)
	end
end

The thing to take away from this is that the tween will not be garbage-collected until all references – including the reference in the Tweens table – are gone. You either need to manually remove that reference or wait until the Tweens table gets garbage-collected itself.


#47

My current code looks like the first block of code you posted. Thanks for the answer!