HEAVY client memory usage problem?

Heya! So we have a pretty big problem when it comes to Client Memory usage in our game. We’ve narrowed it down to a few possible sources using ScriptProfiler (Also our first time using it), and also just researching in general, but I’m not totally sure how to fix them or what exactly I should look up to find help for them.

At the moment the Client Memory usage starts at “2049” MB when you first join the game, but will quickly start going up (To about 4050 so far.) We are pretty positive this must be due to memory leaks, but not totally sure how to find the problem?

(BTW, we do have streaming enabled on already.)

Here’s what I believe causes the higher memory after messing around for a few hours:
[Quick note: Our game uses custom blender morphs for both the default player and selectable characters]

    • When selecting a morph there is a significant spike and it kept shooting up each time we remorphed. Using Scriptprofiler (Duration 1m) we saw that on Server side the highest was”OnServerEvents” at “1412.258” while on Client side the highest was “Delayedthreads” at “1542.443”

(The highest ones in total for Server side were:

at 1412.255
OnServerEvents at 1542.443
Heartbeat at 25.582

While for Client side:

at 3937.116
Delayedthreads at 1542.443
RunService.BindToRenderStep at 1011.55 )

  1. Staying in a single morph and just using animations such as running, jumping, and walking.
    [note: In the beginning I ran into a ton of trouble with animations and in the end settled for a custom animate script. (ps - The jump script uses RenderStepped.)]

(Client:
4395.193
DelayedThreads at 1936.347
RunService.BindToRenderStep at 971.734
Heartbeat at 482.918

[Everything server side stayed at 32.820])

  1. task.wait(). Since DelayedThreads goes up the most on Client side, it led us to this being the possible issue. [There is a chance that there are “wait()”s hidden somewhere that I completely missed when changing them to “task.wait()” after realizing it was better.]

  2. Character Create. We have a section in our game that allows you to select a morph and add accessories to it before loading into the map. This one is a big hog of memory usage, however even when removing it, the memory only drops by about 1k at start but begins climbing again.

  3. Cloning? I assume cloning objects (in this case let’s use the Hair meshes in Character Create as an example of an Object) can cause the memory to go up? However these objects that get cloned are important, such as the Hair for CC, or morphs when changing your player character, so I obviously don’t want to delete them?

  4. Remote events? I’ve read that remote events could take up a lot of memory and we have a lot of them. But if I get rid of them, I have no clue how to make the scripts attached to them work as they should.

  5. Loops. I know these can be a huge issue however we only have 2 scripts that use loops (which are server side.) so i don’t really think this could be the problem but i won’t overlook it just in case.
    [1 script runs every 5 minutes, turning an object invisible and visible again. The 2nd is basically the same but 30 minutes instead of 5.]

-end

We’ve been dealing with a lot of crashes, especially for mobile users or those on low end devices, and sometimes they just can’t play at all since day one. It’s all been a huge pain, but we’re hoping we are on the right track with this memory stuff! However I’m an amateur scripter, having only really started early last year, and trying to figure out where to begin with this particular issue and what to do exactly has been pretty difficult to figure out.

If possible, it would be cool if you could explain the best way to go about this in a simple and easy to understand way? If not then that’s alright. Any help regardless will be incredibly appreciated!

Thank you.

[And just to be super sure, here are some scripts:]

– This is our “Animate” script
local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")


local walkAnim = script:WaitForChild("Walk")
local walkAnimTrack = humanoid.Animator:LoadAnimation(walkAnim)

humanoid.Running:Connect(function(speed)
	if speed == 23 then
		if not walkAnimTrack.IsPlaying then
			walkAnimTrack:Play()
		end
	else
		if walkAnimTrack.IsPlaying then
			walkAnimTrack:Stop()
		end
	end
end)

local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

-- Remeber to select the animtion object and set the id to your own!
local IdleAnim = script:WaitForChild("Idle")
local IdleAnimTrack = humanoid.Animator:LoadAnimation(IdleAnim)

humanoid.Running:Connect(function(speed)
	if speed == 0 then
		if not IdleAnimTrack.IsPlaying then
			IdleAnimTrack:Play()
		end
	else
		if IdleAnimTrack.IsPlaying then
			IdleAnimTrack:Stop()
		end
	end
end)

– Jump script
local RunService = game:GetService("RunService")

local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")

local jumpSound = script:WaitForChild("JumpSound")

local walkAnim = script:WaitForChild("Walk")
local walkAnimTrack = humanoid.Animator:LoadAnimation(walkAnim)
walkAnimTrack.Priority = Enum.AnimationPriority.Movement

local idleAnim = script:WaitForChild("Idle")
local idleAnimTrack = humanoid.Animator:LoadAnimation(idleAnim)
idleAnimTrack.Priority = Enum.AnimationPriority.Idle

local jumpAnim = script:WaitForChild("Jump")
local jumpAnimTrack = humanoid.Animator:LoadAnimation(jumpAnim)
jumpAnimTrack.Priority = Enum.AnimationPriority.Action

idleAnimTrack:Play()

local function move()

	if humanoid.MoveDirection.Magnitude > 0 then
		if not walkAnimTrack.IsPlaying and idleAnimTrack.IsPlaying then
			idleAnimTrack:Stop()
			walkAnimTrack:Play()
		end
	else
		if walkAnimTrack.IsPlaying and not idleAnimTrack.IsPlaying then
			idleAnimTrack:Play()
			walkAnimTrack:Stop()
		end
	end

	if humanoid.Jump then
		jumpAnimTrack:Play()
		jumpSound:Play()
	end

end


RunService.RenderStepped:Connect(move)

 –Sprint script
local UIS = game:GetService('UserInputService')
local Player = game.Players.LocalPlayer or game.Players.PlayerAdded:Wait();
local Character = Player.Character or Player.CharacterAdded:Wait()
local humanoid = Player.Character:WaitForChild("Humanoid")
local PlayAnim


if humanoid then
	local animator = humanoid:FindFirstChildOfClass("Animator")
	if animator then
		local Anim = Instance.new('Animation',animator)
		Anim.AnimationId = 'rbxassetid://14342543643'
		PlayAnim = animator:LoadAnimation(Anim)
	end
end


UIS.InputBegan:connect(function(input)
	if input.KeyCode == Enum.KeyCode.LeftShift and (humanoid.MoveDirection.Magnitude > 0) then
		Character.Humanoid.WalkSpeed = 80
		PlayAnim:Play()
		humanoid:GetPropertyChangedSignal("WalkSpeed"):Connect(function()
			if humanoid.WalkSpeed == 0 then
				PlayAnim:Stop()
			end
		end)
	end
end)


UIS.InputEnded:connect(function(input)
	if input.KeyCode == Enum.KeyCode.LeftShift then
		Character.Humanoid.WalkSpeed = 23
		PlayAnim:Stop()
	end
end)

And heres the server morph event, activated from a GUI button:

local guiMorphEvent = game.ReplicatedStorage.GuiMorph

guiMorphEvent.OnServerEvent:Connect(function(player, morph)
	local char = morph:Clone()
	char.Name = player.Name

	player.Character = char
	char.Parent = workspace
end)

(Note just in case: The server morphs you, not the GUI button, it just fires the server event!)