Disconnect all event connections attached to Player instances after they are removed from the game

As a Roblox developer, it is currently too hard to make sure that all event connections attached to a Player instance are properly disconnected after a player leaves.

At present, event connections to Player instances are not disconnected after the player has left, as one might expect. This means that any event connection to the Player instance is going to cause a memory leak, unless we watch for players leaving the game and manually disconnect the listeners.

The existing behavior is unintuitive. It would not be unreasonable for a developer to assume that instances removed by Roblox are removed responsibly in a way that disconnects event listeners attached to them automatically, as we are constantly encouraged to do by Roblox through the Destroy() method.

If Roblox is able to address this issue, it would improve my development experience because manually disconnecting every event listener attached to a Player after it is removed is both impractical and tedious.

This behavior can be demonstrated using the following code:

local listener

game.Players.PlayerAdded:Connect(function(player)
	listener = player.CharacterAdded:Connect(function(character)
		print("Character Added")
	end)
end)

game.Players.ChildRemoved:Connect(function(player)
	print(listener.Connected) -- true
end)
24 Likes

Would Destroy()ing the Player object on Players.PlayerRemoving fix the problem? I know Destroy() disconnects events so maybe calling Destroy() on the player would fix it temporarily.

3 Likes

You can not call Destroy() on Player instances because their parent property is locked. It throws an error.

1 Like

I’m able to destroy player instances, but it looks like you are unable to destroy them while PlayerRemoving is running. Waiting for the parent to be nil on the player before destroying works for me

local Players = game:GetService"Players"
local Listener
local Player
Players.PlayerAdded:Connect(function(P)
	Player = P
	Listener = Player.CharacterAdded:Connect(function(Character)
		print"Character Added"
	end)
end)
Players.PlayerRemoving:Connect(function()
	while Player.Parent do Player.AncestryChanged:Wait() end
	Player:Destroy()
	print(Listener.Connected) --> false
end)
6 Likes