It does depend on how many connections or things like attributes you have saved to the player/character (or how popular your game is), so it could be less severe. But in general it would be a severe problem
Even if you had a game that only has connected one event to the player/character, since these are never disconnected after the player leaves/character is removed from workspace and users continue to join and leave it would also lead to a memory leak. Just slower. But most of you guys do more than just connecting one simple event.
Yes, sorry for not explaining that thoroughly. i will re-edit it later
Player.CharacterRemoving:Connect(function(Character)
-- Pretend I'm doing other stuff for the character before destroying it
Character:Destroy() -- Memory usage has now been free'd up!
end)
The documentation should also definitely update their page then.
Edit: After reading the update section a bit, some people have claimed that sometimes it wouldn’t even destroy the character automatically on the server:
Some people have also claimed this change has meant that ragdolls for characters are more of a hastle, so it may be preferred to set workspace.PlayerCharacterDestroyBehavour to a different behaviour and again only destroy the character/player when you are done with it.
It’s not a bug and is completely intentional by roblox.
They want you to keep the character/player object even after leaving the game because you may want to use it on their removing events. But destroy them manually once you have used them for your needs.
Problem is, many people did not know roblox doesn’t destroy it automatically.
Roblox’s documentation quote on quote says:
“The engine does not automatically destroy player and character objects”
Although, you’re fix may break if someone uses Immediate SignalBehavior or Roblox changes the default for deletions. You’d want to defer and wrap those calls.
local Players = game:GetService("Players")
local function Destroy(Object: Instance)
task.defer(pcall, game.Destroy, Object)
end
local function OnPlayerAdded(Player: Player)
Player.CharacterRemoving:Connect(Destroy)
end
Players.PlayerAdded:Connect(OnPlayerAdded)
Players.PlayerRemoving:Connect(Destroy)
I’d also mirror this on the client if destroying isn’t replicating.
Don’t these instances simply get garbage collected once all references to them have closed?
In the example bellow, the memory usage goes up very fast, but ends up stabilizing. Just setting the Parent to nil, and ensuring there is no reference to the part, is enough for it to be cleaned up
while true do
for i = 1, 100 do
local Part = Instance.new("Part")
Part.Parent = script
task.delay(1,function()
Part.Parent = nil
end)
end
task.wait()
end
If you remove the task.delay function, the memory never stops going up
It’s not good practice to just parent things to nil instead of destroying them, but it does not necessarily cause memory leaks
Its a bug because they could automatically remove it after the functions are called. there is no player(client) so there is nothing to do with it, maybe only with the physical character but not the player
The problem is when there persists a strong reference to the underlying instance through the engine. Ideally we shouldn’t need :Destroy(). I’m personally of the mindset that it’s the engine’s single most glaring design flaw; and that they really ought to stop expanding its utility—and start investigating other means of treating instances in a more GC compliant fashion.
In the beginning, we did not have :Destroy(). Afterall, the inherent advantage of landing on a garbage collected language, was that scripters would not need to bother themselves with the woes of manual memory management. Unfortunately, it soon-after became apparent that functions connected to signals could possess strong references back to the associated instance—and this cycle of references would prevent that memory from ever being considered eligible for garbage collection. Thus :Destroy() was added. At this time, with what limited utility it had, it could be seen almost as an extension of the events API. Sure, the language is garbage collected; but in the case that you happen to open a connection, either remember to explicitly close it, or call :Destroy() to sever everything bound to the instance’s signals. Undesirable; but simple enough.
In recent years however, it’s unfortunately become again apparent that there exists yet more possibilities for memory leaks within the engine. And it’s been Roblox’s (I think questionable) response, knowing full well the magnitude of this problem, to expand on the behavior of :Destroy() to likewise treat these less common edge-cases. So whereas :Destroy() was once the niche case treatment, it is now much closer to the general rule. But :Destroy() isn’t really a generic cleanup method. As is clear from its evolution, it’s really just a bundle of patchwork solutions targeted at addressing very specific pitfalls. So these unprecedented expectations are actually damaging; because they become the self-same justification for Roblox to further expand the method’s largely undocumented influence.