Connecting events without disconnecting them is probably the most common memory leak nobody talks about

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

1 Like

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 :(

2 Likes

you can use :Once instead of :Connect, :Once automatically disconnects the connection

4 Likes

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.

2 Likes

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.

2 Likes

Now this is something I did not know, I knew about the table.clear() thing though

You cant always tho, like . Touched events and half the events might need to be fired more than once

1 Like

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:

  1. 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.

  2. Functions connected to events are automatically disconnected when the instance the event belongs to is destroyed.

  3. 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