Would this cause a memory leak?

Hello so i was going through the forums trying to look for why my game could be crashing and I saw a topic of memory leaks coming up. i was wondering if code like this could be the cause of memory leaks. I vaguely know what they are, and i know that it happends when something doesn’t get GC’ed, but i dont know if this would actually be a cause of it. If it is, how can i improve my code? any help is appreciated!
Script code:

game.ReplicatedStorage.Quirks.Engine["Recipro Extend"].OnClientEvent:Connect(function(char,effects,Speed)
	
	
	local rootpart = char.HumanoidRootPart
	
	if effects == true then
								
		if workspace:FindFirstChild(char.Name .. "'s EngineExtendCharge") then

			workspace:FindFirstChild(char.Name .. "'s EngineExtendCharge"):Destroy()

		end	
		
		local effectsFold = Instance.new("Folder",workspace)
		effectsFold.Name = char.Name .. "'s EngineExtendEffects"
		
		debris:AddItem(effectsFold,5)
		
		
		coroutine.resume(coroutine.create(function()
			if char:FindFirstChild("ReciproBurst") == nil then

			for i, pipes in pairs(char:GetChildren()) do
				if pipes:FindFirstChild("IsAPipe") then
					local Cgoal = {}
					Cgoal.Size = Vector3.new(0.579, 0.4, 1)
					local Cinfo = TweenInfo.new(0.09,Enum.EasingStyle.Linear)
					local Ctween = TweenService:Create(pipes,Cinfo,Cgoal)
					Ctween:Play()		

					pipes.Color = Color3.fromRGB(75, 72, 74)
					pipes.Material = Enum.Material.Glass	
				end
				end
				
			end	
		end))
		
		
		------------Back large rough Shock------------------
		
		
		
		
		local largerough = script.GiantRough:Clone()
		largerough.Size = largerough.Size / 5
		largerough.CFrame = rootpart.CFrame * CFrame.Angles(math.rad(-90),0,0)
		largerough.Parent = effectsFold
		
				
		coroutine.resume(coroutine.create(function()

		local roughgoal = {}
		roughgoal.Size = largerough.Size * 5 * Speed
		local roughinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
		local roughtween = TweenService:Create(largerough,roughinfo,roughgoal)
		roughtween:Play()
			
		wait(0.30)	
			
		local roughgoal = {}
		roughgoal.Transparency = 1
		local roughinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
		local roughtween = TweenService:Create(largerough,roughinfo,roughgoal)
		roughtween:Play()
		
		end))
		
		
		
		
		------------Dash Shock------------------
		
		
		local DashShock = script.DashShock:Clone()
		DashShock.Size = DashShock.Size / 5
		DashShock.CFrame = rootpart.CFrame * CFrame.Angles(math.rad(180),math.rad(180),0)
		DashShock.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local DashShockgoal = {}
			DashShockgoal.Size = DashShock.Size * 5 * Speed
			DashShockgoal.CFrame = DashShock.CFrame  * CFrame.new(0,0,-24 * Speed)
			local DashShockinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local DashShocktween = TweenService:Create(DashShock,DashShockinfo,DashShockgoal)
			DashShocktween:Play()

			wait(0.30)	

			local DashShockgoal = {}
			DashShockgoal.Transparency = 1
			local DashShockinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local DashShocktween = TweenService:Create(DashShock,DashShockinfo,DashShockgoal)
			DashShocktween:Play()

		end))
		
		------------First Ring------------------


		local RingShock = script.RingShock:Clone()
		RingShock.Size = RingShock.Size / 5
		RingShock.CFrame = rootpart.CFrame * CFrame.Angles(0,math.rad(90),math.rad(-90)) * CFrame.new(0,5 * Speed,0)
		RingShock.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = RingShock.Size * 5 * Speed
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
		------------Second Ring------------------


		local RingShock = script.RingShock:Clone()
		RingShock.Size = RingShock.Size / 5
		RingShock.CFrame = rootpart.CFrame * CFrame.Angles(0,math.rad(90),math.rad(-90)) * CFrame.new(0,45 * Speed,0)
		RingShock.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = RingShock.Size * 5 * Speed
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
		------------Thurd Ring------------------


		local RingShock = script.RingShock:Clone()
		RingShock.Size = RingShock.Size / 5
		RingShock.CFrame = rootpart.CFrame * CFrame.Angles(0,math.rad(90),math.rad(-90)) * CFrame.new(0,75 * Speed,0)
		RingShock.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = RingShock.Size * 5 * Speed
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
		------------Fourth Ring------------------


		local RingShock = script.RingShock:Clone()
		RingShock.Size = RingShock.Size / 5
		RingShock.CFrame = rootpart.CFrame * CFrame.Angles(0,math.rad(90),math.rad(-90)) * CFrame.new(0,100 * Speed,0)
		RingShock.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = RingShock.Size * 5 * Speed
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
		
		------------Fifth Ring------------------


		local RingShock = script.RingShock:Clone()
		RingShock.Size = RingShock.Size / 5
		RingShock.CFrame = rootpart.CFrame * CFrame.Angles(0,math.rad(90),math.rad(-90)) * CFrame.new(0,125 * Speed,0)
		RingShock.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = RingShock.Size * 5 * Speed
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(RingShock,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
		------------Wind Shock------------------


		local Wind = script.Wind:Clone()
		Wind.Size = Wind.Size / 5
		Wind.CFrame = rootpart.CFrame * CFrame.Angles(math.rad(90),math.rad(180),0)
		Wind.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = Wind.Size * 5 * Speed
			Rgoal.CFrame = Wind.CFrame  * CFrame.new(0,-30 * Speed,0)
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Wind,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Wind,Rinfo,Rgoal)
			Rtween:Play()
	
			
		end))

		------------Deep Shock------------------


		local Deep = script.Deep:Clone()
		Deep.Size = Deep.Size / 5
		Deep.CFrame = rootpart.CFrame * CFrame.Angles(0,math.rad(90),math.rad(90))
		Deep.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = Deep.Size * 5 * Speed
			Rgoal.CFrame = Deep.CFrame  * CFrame.new(0,-30 * Speed,0)
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Deep,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Deep,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
		------------HugeRough Shock------------------


		local Rough = script.HugeRough:Clone()
		Rough.Size = Rough.Size / 5
		Rough.CFrame = rootpart.CFrame * CFrame.Angles(math.rad(-90),0,0) * CFrame.new(0,60*Speed,0)
		Rough.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = Rough.Size * 5 * Speed
			Rgoal.CFrame = Rough.CFrame
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Rough,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Rough,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
		------------LargeRough Shock------------------

		local Rough = script.LargeRough:Clone()
		Rough.Size = Rough.Size / 5
		Rough.CFrame = rootpart.CFrame * CFrame.Angles(math.rad(-90),0,0) * CFrame.new(0,75*Speed,0)
		Rough.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = Rough.Size * 5 * Speed
			Rgoal.CFrame = Rough.CFrame
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Rough,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Rough,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
		------------MediumRough Shock------------------

		local Rough = script.MediumRough:Clone()
		Rough.Size = Rough.Size / 5
		Rough.CFrame = rootpart.CFrame * CFrame.Angles(math.rad(-90),0,0) * CFrame.new(0,90*Speed,0)
		Rough.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = Rough.Size * 5 * Speed
			Rgoal.CFrame = Rough.CFrame
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Rough,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Rough,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
		------------SmallRough Shock------------------

		local Rough = script.SmallRough:Clone()
		Rough.Size = Rough.Size / 5
		Rough.CFrame = rootpart.CFrame * CFrame.Angles(math.rad(-90),0,0) * CFrame.new(0,102*Speed,0)
		Rough.Parent = effectsFold

		coroutine.resume(coroutine.create(function()

			local Rgoal = {}
			Rgoal.Size = Rough.Size * 5 * Speed
			Rgoal.CFrame = Rough.CFrame
			local Rinfo = TweenInfo.new(0.5,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Rough,Rinfo,Rgoal)
			Rtween:Play()

			wait(0.30)	

			local Rgoal = {}
			Rgoal.Transparency = 1
			local Rinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
			local Rtween = TweenService:Create(Rough,Rinfo,Rgoal)
			Rtween:Play()

		end))
		
	elseif effects == "Charging" then
		
		local charingfolder = Instance.new("Folder",workspace)
		charingfolder.Name = char.Name .. "'s EngineExtendCharge"
		
		
		debris:AddItem(charingfolder,1)
		
		local ball = script:WaitForChild("Ball"):Clone() 

		ball.Parent = charingfolder

		ball.CFrame = char.RightUpperLeg.CFrame

		ball.Name = "ExploGrenChargeBall"		

		local ball2 = script:WaitForChild("Ball"):Clone() 

		ball2.Parent = charingfolder

		ball2.CFrame = char.LeftUpperLeg.CFrame

		ball2.Name = "ExploGrenChargeBall2"	

		local weld = Instance.new("WeldConstraint")
		weld.Part0 = char.RightLowerLeg
		weld.Part1 = ball
		weld.Parent = char.RightLowerLeg

		local weld = Instance.new("WeldConstraint")
		weld.Part0 = char.RightUpperLeg
		weld.Part1 = ball2
		weld.Parent = char.RightUpperLeg	
		
		
		coroutine.resume(coroutine.create(function()
			if char:FindFirstChild("ReciproBurst") == nil then

			for i, pipes in pairs(char:GetChildren()) do
				if pipes:FindFirstChild("IsAPipe") then
					local Cgoal = {}
					Cgoal.Size = Vector3.new(1.5, 1.5, 1.5)
					local Cinfo = TweenInfo.new(1,Enum.EasingStyle.Linear)
					local Ctween = TweenService:Create(pipes,Cinfo,Cgoal)
					Ctween:Play()		
					
					pipes.Color = Color3.fromRGB(2, 225, 210)
					pipes.Material = Enum.Material.Neon	

				end
				end
				
				
			end	
		end))

		
		coroutine.resume(coroutine.create(function()
			while workspace:FindFirstChild(char.Name .. "'s EngineExtendCharge") do

				local randomvar = math.random(-360,360)
				ball.Orientation = ball.Orientation + Vector3.new(randomvar,randomvar,randomvar)

				local charge = script:WaitForChild("ChargeFXO"):Clone()
				charge.CFrame = ball.CFrame * CFrame.new(0,-3,0)
				charge.Orientation = Vector3.new(ball.Orientation.X,ball.Orientation.Y,ball.Orientation.Z)
				charge.Parent = charingfolder

				local posgoal = {}
				posgoal.CFrame = ball.CFrame
				posgoal.Size = charge.Size / 5
				posgoal.Transparency = 1	
				local posinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
				local postween = TweenService:Create(charge,posinfo,posgoal)
				postween:Play()

				task.wait(1/60)
			end 
		end))

		coroutine.resume(coroutine.create(function()
			while workspace:FindFirstChild(char.Name .. "'s EngineExtendCharge") do

				local randomvar = math.random(-360,360)
				ball2.Orientation = ball2.Orientation + Vector3.new(randomvar,randomvar,randomvar)

				local charge = script:WaitForChild("ChargeFXY"):Clone()
				charge.CFrame = ball2.CFrame * CFrame.new(0,-3,0)
				charge.Orientation = Vector3.new(ball2.Orientation.X,ball2.Orientation.Y,ball2.Orientation.Z)
				charge.Parent = charingfolder

				local posgoal = {}
				posgoal.CFrame = ball2.CFrame
				posgoal.Size = charge.Size / 5
				posgoal.Transparency = 1	
				local posinfo = TweenInfo.new(0.2,Enum.EasingStyle.Linear)
				local postween = TweenService:Create(charge,posinfo,posgoal)
				postween:Play()

				task.wait(1/60)
			end 
		end))

		
		
		
	end
end)

Just post your code in text for using the script format tool, then we would be happy to try to help.

1 Like

alright noted. I wont be posting the other one because its essentially the same code just used differently.

I did not see anything in that script that would cause a memory leak. You should be good. But in case you are not content, just make sure you clean up anything that is unused and break loops when no longer necessary.

ah okay thank you. also one more question: can using too many coroutines cause lag?

Depends on the content within them. Anything can cause lag if it is not properly managed.

Say you run your remote event every second then sure that would lag your game. But if it is only like once every 10 seconds or so, it should be fine.

Ah okay, just worried that I’m incorrectly yielding in a way that causes buildup over time. Thank you for the info!

Spawning too many threads (coroutines) can be slow. It seems to be 5x slower than just running a function, to just start up that function.

It’s fine to use threads, that’s only a worry in contexts like having thousands of connections to RunService events which run every frame or example.

But, you should be fine.
However, you shouldn’t use coroutine.resume.
Use task.spawn (or at least coroutine.wrap) instead.

task.spawn(function()
    -- Spawns a thread but without any of the issues that coroutine.resume can cause.
end)

I won’t explain exactly what issues there are, because it’s a lot but task.spawn is just a better, newer method to go about it.

coroutine.resume(coroutine.create(function())) is essentially the same as coroutine.wrap(function())(), task.spawn() is good but coroutines are different, you can’t really compare the two, task.spawn should be used over the global spawn function however.

coroutine.resume(coroutine.create(func)) is definitely not the same as coroutine.wrap.

Resuming routines using coroutine.resume has debugging issues.

Test this on your game:

coroutine.wrap(function()
    error("This error shows up")
end)()

coroutine.resume(
    coroutine.create(function()
        error("This does not")
    end)
)

task.spawn(function()
    error("This error shows up")
    -- task.spawn is still better than coroutine.wrap, for speed, and syntax. Other than that it's similar.
end)

THE TASK LIBRARY IS ANOTHER LIBRARY TO MANIPULATE COROUTINES!!! I don’t know why it’s such a common misconception that it’s not, or that it’s some other type of thing, IT’S NOT. It’s basically a library to mess with coroutines, that is updated, and more “made for Roblox”. It resumes routines through the task scheduler which fixes a lot of issues, like this.

You can get an error out of coroutine.resume, but it’s more useless code, and you still lose stack traces (the info about where that error really came out and what was called and tuned before that).
And a lot of other issues with “closures.”

Actually not, because task.spawn runs the function immediately, while spawn basically does a wait(). The better replacement would be task.defer which is not quite a wait, but doesn’t spawn immediately.

task.spawn is an optimal replacement for fastSpawn by quenty (not existent anymore), and for the more common coroutine.wrap.

coroutine.wrap(function()
	print("This error shows up")
end)()

coroutine.resume(
	coroutine.create(function()
		print("This does not")
	end)
)

Both show, error behaving differently is due in part to the way in which stacks work.

I respect the effort in your post however.

You’re printing, that works. Using error does not. The only error message you get is from the string returned by coroutine.resume, but again that doesn’t contain stack trace info, and using task.spawn is much more convenient.

Understandable. I do notice this is an issue with coroutines and it does make it harder to identify issues in my game so i might switch over to it for that sole reason.

1 Like