Question about Memory Leak

Correct, connections can be either manually disconnected (:Disconnect(), .Connected → false). Moreover, the signal is going to disconnect once the object it is bound to is destroyed.

Consider the summarized example
local numberValue = Instance.new("NumberValue")

local connection; connection = numberValue.Changed:Connect(function(newValue)
	print(newValue)
end)

task.spawn(function()
	while numberValue do
		numberValue.Value += 1
		task.wait(1)
	end
end)

task.wait(1)
numberValue:Destroy()
print(connection.Connected) --> false

(Side note: the reference to number value is not lost yet - number value base is still defined - so it won’t be subject to garbage collection until we set numberValue to nil and thus lose all (strong) reference.)

The CharacterAdded will get disconnected once Player instance is properly destroyed. Does the engine remove it automatically? It should, but to be on the safe side, I hook something like the following to my PlayerRemoving connections.

game:GetService("Players").PlayerRemoving:Connect(function(player)
	-- save data
	-- destroy character when you don't need it anymore
	task.wait(100) -- a reasonable wait time
	player:Destroy()
end)

A useful announcement post regarding player:Destroy().

A small discussion other devs and I had regarding player and character removal, espeically character.



Some additional examples with characte resetting.

NumberValue outside character, not destroyed nor disconnected.
local PlayerService = game:GetService("Players")

local numberValues = {
	Instance.new("NumberValue"), Instance.new("NumberValue")
}

task.spawn(function()
	while true do
		task.wait(1)
		numberValues[1].Value += 1
		numberValues[2].Value += 10
	end
end)

PlayerService.PlayerAdded:Connect(function(player)
	local n = 0
	
	player.CharacterAdded:Connect(function(character)
		n += 1
		if n > 2 then return; end
		
		numberValues[n].Changed:Connect(function(newValue)
			print(newValue)
		end)
	end)
end)
NumberValue inside character, with commented code that destorys the character.
local PlayerService = game:GetService("Players")

local weakReferences = setmetatable({}, {__mode = "v"})

PlayerService.PlayerAdded:Connect(function(player)
	local n = 0
	
	player.CharacterAdded:Connect(function(character)
		n += 1; local _n = n -- a private copy of n
		
		weakReferences[_n] = Instance.new("NumberValue")
		weakReferences[_n].Parent = character
		
		weakReferences[_n].Changed:Connect(function(newValue)
			print(newValue)
		end)
		
		while weakReferences[_n] do
			weakReferences[_n].Value += 1
			task.wait(1)
		end
	end)
	
	--player.CharacterRemoving:Connect(function(character)
	--	character:Destroy()
	--end)
end)

In the second example, you’ll notice how .Changed isn’t getting disconnected, which is still quite a strange phenomenon, compared to the very first example at the top of the post. Uncommenting the commented lines to eventually destory the character yields the expected result.

3 Likes