When this property is set to Enabled, and a player leaves an experience while they are spawned in, does Destroy also get called on their Character, if it exists?
Player
itself is still accessible and if you happen to have stored instance references to child instances, those will be valid as well (but without any children).
Properties, including UserId
are still valid and will contain original values, even after taking a delay.
So to clarify, player children won’t be accessible but the player instance and properties (userid, etc) itself will be accessible (assuming for a bit before its gone)?
Yes.
And ‘a bit’ is ‘until existing strong references remain’.
There is still a chance that custom code will hold onto some instances for a long time; our hope in that case is that server will at least have an opportunity to collect hundreds of other child instances, freeing most memory.
Will the destroy signal/event be pinged when the character is being destroyed this new way.
Yes, Destroying
signal is still triggered just before the Instance is actually destroyed.
So all this time, every respawned character was being buried in a metaphorical graveyard under nil, instead of a full purge?
I was already doing this manually in my games, but having it happen auto-magically is a nice change. I’ve suspected that a lot of the server crashes I see complained about here were related to this but unless someone has been coding since the old days; it’s hard to explain good memory management here.
I would suspect that yes it would because of those asynchronous calls you have in it. It looks like when the player leaves, the server has one shot of doing the work and anything that delays (task wait, async, etc.) will be ignored and the player object deleted if I’m reading the technical info correctly here.
Wow, didn’t even know this was a problem. I always thought that they were :Destroy()'d. Good to know I have TONS of memory leaks that need fixing.
What’s funny about this is just yesterday I noticed that the parent of the character gets set to nil, so I made a system to manually destroy them. lol
Nice update, hope this will fix memory leaks!
Does this change apply to the Player:LoadCharacter
method? My game has a custom character loader and I currently destroy the old character manually.
It’s so nice to see that work is finally going into correcting this stone age issue and that the behaviour will become default. There’s virtually no reason at all for players and characters not to get destroyed when they’re no longer in use and this missing contract caused a lot of obscure and hidden bugs with developer code if not applying heavy workarounds.
I’ll be enabling this immediately and experimenting across all my projects upon their next updates. Players and characters are some of the most memory-hogging features in my experiences and I would not be surprised to learn that some of my memory consumption over time is related to both.
THANK YOU. As someone who used to experience server crashes, this is great news.
Although, is there any news about the memory leak that occurs when models (or in my case, vehicles) are destroyed (even when there are no variables holding the object)? Here’s a post about it:
I will be using custom characters a lot as well, along with Player.CharacterAutoLoads
disabled.
In this case it seems the workflow shouldn’t differ from what you’re doing right now, as the new feature will clean up the old character if it still exists when the new one is added, as visible in the code below.
CharacterAdded
always fires before Destorying
.
The new feature is pretty neat, and is compatible with manual removal of the character.
Code (try resetting)
local Players = game:GetService("Players")
Players.CharacterAutoLoads = false
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
local humanoid = character:WaitForChild("Humanoid")
humanoid.Died:Once(function()
task.wait(3)
player:LoadCharacter()
end)
character.Destroying:Once(function()
print("Character destroying")
end)
print("Character added")
end)
player:LoadCharacter()
end)
Wow, honestly, this is a real announcement, unlike the other one.
Also, this feature is super cool tbh.
Yooo, update that fixes long present memory leak?
That’s a W in my book.
I didn’t even know characters were just parented to nil, there was a memory leak I didn’t even know existed.
Love this update. Now I can delete all my player and character handling on remove!
Does this mean if a character dies I don’t have to update the character variable in scripts?
Connecting to Players.PlayerAdded
and Players.PlayerRemoving
does not necessarily create a memory leak, because the connection is only related to the Players
service. If you maintain references to the Player
argument that gets passed by those events however, that’s where you could see a memory leak.
To give some examples:
Fixed by this change (because the CharacterAdded
connection would have maintained the reference under current behavior)
game:GetService("Players").PlayerAdded:Connect(function(player: Player)
player.CharacterAdded:Connect(function()
print("New character!")
end)
end)
Not fixed by this change (because the instance reference exists indefinitely in the AllPlayers
table)
local AllPlayers = {}
game:GetService("Players").PlayerAdded:Connect(function(player: Player)
AllPlayers[player] = true
end)
The above example, manually patched
local AllPlayers = {}
game:GetService("Players").PlayerAdded:Connect(function(player: Player)
AllPlayers[player] = true
end)
game:GetService("Players").PlayerRemoving:Connect(function(player: Player)
AllPlayers[player] = nil
end)
As for a reduction in server memory usage, you will a change to the rate at which memory increases if you had a memory leak patched by this. It will likely not have an impact on baseline memory usage.