Animation server memory leak on every character respawn — reproducible on a bare baseplate

Every character reset causes Animation memory to spike and never come back down. Repeated resets compound. The growth is monotonic and doesn’t recover, eventually contributing to server/client PlaceMemory climbing into the multiple-GB range over long uptimes and causing Out-of-Memory crashes on live servers (server uptime ~32-40 hours before crash, matching the accumulation rate we’ve observed).


Affected Game

System Info:
CPU: Intel® Core™ Ultra 5 226V, 8 cores, ~2.1GHz
RAM: 16,384 MB (16 GB)
GPU: Intel® Arc™ 130V, 8 GB
DIRECTX 12

Expected behavior

Resetting/respawning a character should not cause a permanent, cumulative increase in the Animation memory category (Developer Console → Memory → PlaceMemory → Animation). Memory should return to roughly its prior baseline after the new character’s animations finish loading.
Reproduction steps (100% consistent):

  1. Open a brand-new, empty Baseplate template in Studio
  2. Start a local server / playtest.
  3. Open the Developer Console (F9) → Memory tab → expand PlaceMemory → Animation.
  4. Note the baseline value.
  5. Reset your character (default Roblox reset, or Player:LoadCharacterAsync()).
  6. Observe: Animation value spikes and does not return to baseline.
  7. Repeat resets → value keeps climbing, indefinitely, with no recovery (or very small ones).

No custom scripts are involved. This is triggered purely by the engine’s own default character/Animate script reloading its built-in animations (walk/run/jump/idle/fall) onto the newly created Animator on each respawn.

3 Likes

Also having issues with memory leaks, but not the same one described here. I explained my issue in a reply to this report.

3 Likes

Thanks for reporting we have a fix in queue and will release it next week.

1 Like

Even worse : Duplicating Rigs (Animators and AnimationControllers have a WAY higher impact that could increase memory by tens or hundreds of mb) ON CLIENT makes the SERVER animation and instance memory go up, so esentially anyone that would just spam :Clone() and :Destroy() on a simple rig, could just crash any server

This is never collected. Only around ~1mb out of ~5-6mb (from my test place)

I also notice it happens on player join as well, tested in studio server and client mode empty baseplate with one client to monitor animation memory and another to leave and rejoin on repeat. Leaving doesn’t lower or increase server animation memory usage, but joining again seems to the moment a new player’s character spawns in

1 Like

Bump. It looks like exploiters are crashing servers using memory using this. They crashed all my games servers

We’ve shipped the fix, please let us know if the issue persists.

3 Likes

Thank you, I will diagnose my game for the next couple of days and let you know if anything goes wrong!

Same issue is still happening to us. Memory usage goes up nearly 2mb from me respawning, walking and jumping around 3 times. I could replicate it in “Swarm Survival” and on a empty baseplate. On a empty baseplate the increments of each reset were smaller but still existed. About .5mb per reset.

This was produced by a server script repeatedly loading, playing animations, resetting the character and repeating.

Repro Code:

I ran this in the dev console command line twice (both AI generated):

task.spawn(function() local p=game.Players:GetPlayers()[1] local ids={"rbxassetid://913376220","rbxassetid://913402848","rbxassetid://507766388","rbxassetid://507766666","rbxassetid://507765000","rbxassetid://507767968","rbxassetid://507770239","rbxassetid://507770677","rbxassetid://507784897"} while p and p.Parent do local c=p.Character or p.CharacterAdded:Wait() local h=c:WaitForChild("Humanoid") local a=h:FindFirstChildOfClass("Animator") or Instance.new("Animator",h) local n=0 for i=1,200 do local anim=Instance.new("Animation") anim.AnimationId=ids[(i-1)%#ids+1] local ok,t=pcall(function() return a:LoadAnimation(anim) end) if ok and t then t:Play() n+=1 end end print(("[StressTest] %d/200 loaded, mem=%.1fMB"):format(n, game:GetService("Stats"):GetTotalMemoryUsageMb())) task.wait(2) p:LoadCharacter() p.CharacterAdded:Wait() task.wait(0.5) end end)

For a plain script under ServerScriptService:

-- StressTest_AnimationLeak (ServerScriptService)
local Players = game:GetService("Players")
local Stats = game:GetService("Stats")

local NUM_TRACKS = 200
local RESET_DELAY = 2

local ANIMATION_IDS = {
	"rbxassetid://913376220", -- walk
	"rbxassetid://913402848", -- run
	"rbxassetid://507766388", -- idle 1
	"rbxassetid://507766666", -- idle 2
	"rbxassetid://507765000", -- jump
	"rbxassetid://507767968", -- fall
	"rbxassetid://507770239", -- climb
	"rbxassetid://507770677", -- swim idle
	"rbxassetid://507784897", -- swim
}

local function loadAndPlay(character)
	local humanoid = character:WaitForChild("Humanoid")
	local animator = humanoid:FindFirstChildOfClass("Animator") or Instance.new("Animator", humanoid)

	local loaded = 0
	for i = 1, NUM_TRACKS do
		local id = ANIMATION_IDS[(i - 1) % #ANIMATION_IDS + 1]
		local anim = Instance.new("Animation")
		anim.AnimationId = id

		local ok, track = pcall(function()
			return animator:LoadAnimation(anim)
		end)

		if ok and track then
			track:Play()
			loaded += 1
		end
	end

	print(("[StressTest] Loaded %d/%d tracks on %s (mem: %.1f MB)")
		:format(loaded, NUM_TRACKS, character.Name, Stats:GetTotalMemoryUsageMb()))
end

local function runLoop(player)
	while player and player.Parent do
		local character = player.Character or player.CharacterAdded:Wait()
		loadAndPlay(character)

		task.wait(RESET_DELAY)

		player:LoadCharacter()
		player.CharacterAdded:Wait()
		task.wait(0.5)
	end
end

-- Grab the first player currently in the game
local firstPlayer = Players:GetPlayers()[1]
if firstPlayer then
	task.spawn(runLoop, firstPlayer)
else
	-- If script runs before anyone's joined, wait for the first one
	local conn
	conn = Players.PlayerAdded:Connect(function(player)
		conn:Disconnect()
		task.spawn(runLoop, player)
	end)
end

Still happening for me as well, had no idea a fix for this was even pushed as my thread is yet to be acknowledged despite being older than this one