Making a "maid" script for controlled garbage collection

Hi, first post on the forum, so excuse me if this is a bit convoluted.

I’m working on a larger game project at the moment, and I figured it might be smart to make a controlled garbage collection script/module I can call up any time I need it.

It works by simply having all my variables inside a table inside code that I know is will be temporary. Then I can just pass those variables to the module and it does all the work without much issue. This works, I think? It causes a single frame freeze pictured below, but I think it does what it’s supposed to.

What I’m wondering about is if this is necessary? The use case I have currently is for a UI that gives weapons to the player upon spawning in. This is a UI that is given to you upon spawning in from StarterGUI, and wont be needed afterwards – which is why I deem it temporary.

Is there also a better method to doing this? Because the client freeze feels like a sign that I’m doing something wrong. That’s all. Any feedback is appreciated. Thanks.

LocalScript where it's called
maid = require(game:GetService("ReplicatedStorage").maid)
event = game:GetService("ReplicatedStorage").Events.GiveWeapon

Variables = {
	mainUI = script.Parent,
	pressed = false,
	button = ""
}

local func

local function Presser(button)
	func:Disconnect()
	func = nil
	
	print(button)
	event:FireServer(button.Text)
	
	maid.CleanAll(Variables)
	event = nil
	maid = nil
	button = nil
end

for i,name in pairs(Variables.mainUI.List:GetChildren()) do
	if name:IsA("TextButton")  == true then
		if name.Name ~= "Template" then
			Variables.button = name
			
			func = Variables.button.Activated:Connect(function()
				Presser(Variables.button)
			end)
		end
	end
	
end
Module Code
local rus = game:GetService("RunService")

local maid = {}

function maid.CleanAll(Variables) -- fully cleans given table
	for num, item in pairs(Variables) do
		if type(item) == ("userdata") then -- if it's an instance
			if item.Parent == game then -- if it's a service
				item = nil
			else -- if it's anything else but a service
				item:Destroy()
				item = nil
			end
		else -- if it's a non-instance object
			item = nil
			
		end
	end
	
	Variables = nil
end

function maid.VariableClean(Variables) -- cleans variables from table
	for num, item in pairs(Variables) do
		task.wait()

		if type(item) ~= ("userdata") then -- if it isn't an instance
			item = nil
		else

		end
		
	end
	
	Variables = nil
end

function maid.InstanceClean(Variables) -- cleans instances from table
	for num, item in pairs(Variables) do
		task.wait()

		if type(item) == ("userdata") then -- if it's an instance
			if item.Parent ~= game then -- if it's a instance
				item:Destroy()
				item = nil
			end
		end

	end
	
	Variables = nil
end

return maid

1 Like

Variables are collected automatically in Roblox, so you don’t need it, it will just possibly cause leaks instead of helping

What i’ve did a year ago is making Cleaning module that isn’t periodical clear, rather just insta-destroyer of custom objects, i’ve only included rblx objects such as:

  • Threads
  • Instances
  • Connections
  • Metatables
  • Setting table keys to nil + recursion

If i want to destroy custom objects like table that’s OOP object, or DOD table, i just create Destroyer method that i’ll call every time, it’s working as i didn’t encountered serious memory leaks in a while

EDIT: You really don’t have to care about memory leaks before you make your game, then you can rewrite it or fix it, if you have a game, and it’s popular - you know it’s worth making it actually good and optimized

Your code isn’t doing what you think it’s doing. In the for loop of your VariableClean function, doing item = nil sets the item variable to nil, but it does not modify the contents of Variables in any way. The same thing goes for the Variables parameter; doing Variables = nil does not actually modify the table that Variables is referencing – it just tells the script that you want the Variables parameter to stop referencing the table. You need to set the keys of the table to nil directly:

function maid.VariableClean(Variables)
	for num in pairs(Variables) do -- don't need the item variable
		Variables[num] = nil -- remove the table key directly
	end
    -- no point in doing Variables = nil
end

When the function ends, the Variables parameter ceases to exist thus removing its reference to the table you passed in. Edit: Even if you do Variables = nil in the module script, the Variables reference in the local script still doesn’t get cleaned when you do maid.CleanAll(Variables) (the Variables parameter in the module script is nil but the Variables in the local script is still referencing the same table thus leaking memory anyway). If you’re using a language with pointers like C then you can achieve something like this, but Lua doesn’t give you precise control over memory addresses. You still have to set the Variables in the local script to nil every time you call maid.CleanAll:

-- local script
maid.CleanAll(Variables)
Variables = nil

I wouldn’t recommend doing this anyway. Having to keep all your variables in a table adds extra overhead plus it isn’t necessary for good memory management. There are open-source maid modules that you can use if you want, but I manage 17,000 lines of code just fine without a maid. My servers run up to 24 hours at a time and don’t experience any growth in memory. You just have to watch out for upvalues in event callbacks.

2 Likes

Thanks for the replies.

I didn’t realize this, so thank you for this. Your explanation is very clear and concise and I understand now, so cheers for that.

I just have a habit of over engineering everything, but I guess it’s fair enough to only really worry about it later. But alright, I’ll scrap the idea if it isn’t necessary. And if it turns out that I need something like that later on, then I’ll look into it then.

I think I recall reading about this some time ago. I’ll definitely go through that thread, so cheers again for linking it.

But yea, thank you for the help.

If you worry about overengineering, then maybe instead of thinking of game development that “Coins clicking simulator” is the only and single continuos project, you might think like “Coins clicking simulator - MVP” and then “Coins clicking simulator - Beta” ect. so you see that for instance “i’m making MVP, so i don’t need memory collection, but i need gui that when you click it gives you how much coins you have” ect. this might help you a little

3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.