Does game.Debris:AddItem() throttle?

Using too many wait()s simultaneously will cause significant performance dip or in some cases will cause your code to infinitely yield. After testing game.Debris:AddItem(), I realised it’s waiting in intervals similar to wait(), so my concern is, if I use too many game.Debris:AddItem() simultaneously, will that cause some throttling and thus kill my performance?

This was the test I realised:

local lastTime = os.clock()

local p = Instance.new("Part", workspace)
p.AncestryChanged:Connect(function()
	print("Destroyed after", os.clock() - lastTime) -- This prints around 0.03
end)

game.Debris:AddItem(p, 0.01)

Should I instead opt to using something like this?

local function Debris(item, period)
	task.spawn(function()
		task.wait(period)
		if item and item.Parent ~= nil then
			item:Destroy()
		end
	end)
end

The function above will never throttle because task.wait() uses heartbeat, and if you have any suggestions to make it better, please share.

5 Likes
-- Credits: @LucasMZReal (https://github.com/LucasMZReal)
local function Destroy(instance, duration)
    task.delay(duration or 0.0166666667, game.Destroy, instance);
end
6 Likes

I guess this is the successor to game.Debris:AddItem(), thank you for sharing this. And just for convenience, might as well add this

local function Destroy(instance, duration)
	task.delay(duration or 0.01, game.Destroy, instance)
end
3 Likes

I’m not convinced that it’s worth abandoning Debris Service. I just ran a benchmark in Studio with this code:

local debris = game:GetService("Debris")

task.wait(5)

local folder = Instance.new("Folder")
folder.Parent = workspace

local tasktimes = table.create(100)

for test = 1, 100 do
	
	local start = os.clock()
	for i = 1, 1000 do
		local part = Instance.new("Part")
		part.Position = Vector3.new(math.random(-500,500),math.random(-500,500),math.random(-500,500))
		part.Parent = folder
		
		task.delay(1, function() part:Destroy() end)
	end

	task.wait(2)
	local stop = os.clock()
	tasktimes[test] = (stop - start)
end

local tasktotal = 0
for i = 1, 100 do
	tasktotal += tasktimes[i]
end

local debristimes = table.create(100)
for test = 1, 100 do

	local start = os.clock()
	for i = 1, 1000 do
		local part = Instance.new("Part")
		part.Position = Vector3.new(math.random(-500,500),math.random(-500,500),math.random(-500,500))
		part.Parent = folder

		debris:AddItem(part,1)
	end	

	task.wait(2)
	local stop = os.clock()
	debristimes[test] = (stop - start)
end

local debristotal = 0
for i = 1, 100 do
	debristotal += debristimes[i]
end

print("Duration Average for task.delay: "..(tasktotal/100))
print("Duration Average for debris service: "..(debristotal/100))

And got these results:
image

So it really seems to me like they take about the same amount of time either way.

3 Likes

While this is a good benchmark, it’s running on your presumably powerful machine with no external load on the environement. The real tests will happen in a server full of players and other variables that come into play, and according to your benchmark, task.delay will help ease up a lot of load on the server thus yielding better experience.

1 Like

Honestly this wouldn’t work if the script was deleted.

The main reason debris exists is to be 100 % sure that something will be deleted.

1 Like

It does work though? Or at least did in my end.

Here’s the code I used:

-- debris
game:GetService("Debris"):AddItem(workspace.Baseplate, 25);
script:Destroy();

-- no debris
local function Destroy(instance, duration)
	task.delay(duration or 0.0166666667, game.Destroy, instance);
end

Destroy(workspace.Baseplate, 25);
script:Destroy();

I ran them separately.

1 Like

I think I remembered the issue wrong. Actually the problem is that if the object is already destroyed (like by another script or by falling to the void) then the code would error.

1 Like
-- script 1:

local function Destroy(instance, duration)
	task.delay(duration or 0.0166666667, game.Destroy, instance);
end

Destroy(workspace.Baseplate, 25);

-- script 2
workspace.Baseplate:Destroy();

And it still worked without any errors.

Debris is actually the culprit here. By the time the service is loaded, Baseplate is already destroyed and thus it errors:

-- script 1
game:GetService("Debris"):AddItem(workspace.Baseplate, 25);
workspace.Baseplate:Destroy(); --> Baseplate is not a valid member of Workspace "Workspace" 

-- script 2:
workspace.Baseplate:Destroy();
2 Likes

1/60th of a second, which for most Roblox users would be 1 frame.