ok so i was getting random lag spikes in my game and spent forever trying to figure out why. turned out i had a massive memory leak from something super simple that i never thought about.
every time a player respawned i was reconnecting events like Touched, Changed, or custom RemoteEvents without ever disconnecting the old ones. so after like 10 respawns you’d have 10 copies of the same event all running at the same time — and they never get cleaned up because Luau has no idea you’re done with them.
-- this looks fine but its actually a leak
character.Humanoid.Died:Connect(function()
handleDeath()
end)
-- every respawn adds another connection on top
-- the fix: store the connection and disconnect it first
local conn
conn = character.Humanoid.Died:Connect(function()
handleDeath()
conn:Disconnect()
end)
after i fixed this my game went from lagging after like 5 minutes of playing to running completely smooth. the difference was insane honestly
has anyone else had this problem? and is there a cleaner way to manage connections at scale — like a connection manager or something? would love to hear how other devs handle this
yea pretty much all scripts in my game have this except the newer ones as I found this out a few weeks ago. Now i have to go back and change them all :(
Since the character gets destroyed and another character spawns, shouldn’t the event disconnect because the Humanoid has Destroy called, deleting all connections? I think this shouldn’t cause a memory leak by itself.
In proper cases (maybe leaving a connection when a object with a specific tag has the tag deleted) this is needed though.
If you want, you can store all of your connections in a table, that way, they are all in one place, so when you want to disconnect them, you can just loop through the table.
The concepts surrounding proper event usage are standard and well documented on the relevant API reference pages. Developers either grasp these concepts already or develop them correctly when learning the material. Developers can also form an incomplete understanding that naturally evolves. This is why event-based memory leaks aren’t a headline topic.
The biggest source of long-term misunderstanding is heavy reliance on YouTube tutorials. Introductory material often fails to cover important functions and behaviours of engine features.
Managing your memory is a critical component to all software engineering, and there are leaks of different forms to be discovered. For events, open-source tooling does exist to aid in their management, with lighter to more feature-packed resources like the Maid and Janitor classes, respectively.
What there is to know now:
Functions connected to events are represented by RBXScriptConnection objects. These objects inform you of the function’s connectivity status, and enable you to disconnect them with discretion.
Functions connected to events are automatically disconnected when the instance the event belongs to is destroyed.
Functions can have one-time connectivity to an event through the shorthand RBXScriptSignal:Once method.
On a related note, you may like to learn about object pooling:
don’t humanoids automatically remove connections after being destroyed? I think this specific case happens because you store a reference to it (in the conn forward-declared variable) so it stays active instead of being cleaned