Am I using garbage collection correctly?

Am I using garbage collection correctly?

Hi I’m trying to make a simple cleanup function that makes everything inside of my table eligible for garbage collection. Here is my simple script:

function SpaceshipGeneration:Cleanup() -- Garbage collection
	local function Clean(tbl)
		for key, value in tbl do
			if type(value) == "table" then
				Clean(value)
			elseif typeof(value) == "Instance" then
				value:Destroy()
			end
			tbl[key] = nil
		end
	end

	Clean(self)
	setmetatable(self, nil)
end

Anyways I’m not entirely sure HOW garbage collection works. However what I’ve done is destroy instances and set other things to nil. Here is a small piece of code that uses it:

local function GenerateShip(OptionalRooms: number, EventChance: number)
	local ship = shipGeneration.new(OptionalRooms, EventChance)
	local info = ship.Info
	
	warn(ship)

	while info.TotalRoomsNeeded ~= ship:GetCurrentNum() do
		
		if GetNum(info.Paths) == 0 then -- Restarts the process and cleans up the ship
			ship:Cleanup()
			ship = nil
			GenerateShip(OptionalRooms, EventChance)
			return
		end
-----------------------------------------------

If the generation gets cut off by both paths it will redo the path. And to do that it will have to destroy the entire ship object which is a table with everything in it.
What I’ve done is use the :Cleanup() function and then set the ship to nil.

I want to know if setting the ship to nil is required as I’ve just put that in there just in case. If it is, should I set “info” to nil too?

ship:Cleanup()
ship = nil
print(ship) -> nil
print(info) -> {} -- info = ship.Info

Since it still prints a table does that mean its still taking up space??? If it is should I set that to nil too?

My main question though is if this system works as intended and that Roblox’s garbage collection system will cleanup the discarded ship object. If there are any things I can do to optimize or improve this system please let me know!

It should be fine. In the basic of basic terms, the garbage collector works by scanning and seeing if values are referenced anywhere in scripts. If they aren’t referenced, they get cleaned.

A value can become unreferenced in multiple ways. For example, if you had a function:

local function doStuff()
    local x = 5
    local y = 7
    return x + y
end

as soon as this function finishes, x and y are no longer referenced anywhere because they have gone out of scope. So the GC goes ahead and cleans it up.

In terms of your system, it should be just fine. When an Instance is destroyed, all that does is set the Parent property to nil, lock the Parent property, and calls Destroy on all children. The reference to the instance will still exist in the variable in your code, until it goes out of scope - which you’ve accelerated by setting to nil. As for info, that also won’t be collected until it goes out of scope is is set to nil.

But I really wouldn’t worry; setting variables to nil is generally a bit overkill. You’d be fine just :Destroy()ing the ship and letting the GC do the rest.

Thanks so much for clearing that up.
If you’re alright with a few last questions. Might I ask if setting non-instance values to nil affect memory more than just letting the garbage collector handle it? Or is it fine doing both ways and I just over did it.

Also to clarify, you’re saying I do not have to set ship to nil and any of the values in the table. I just have to destroy instances and stop referencing the object all together. So if I return a function and never use those variables again, they will be cleaned up.

1 Like

All it means is it might get cleaned up very slightly faster, but it wouldn’t be noticeable in terms of performance. Letting them go out of scope would be fine, but you can set them to nil if you want.


It depends. For your table, if it contains any instances, you should absolutely destroy them if they are no longer needed; if they remain parented to the game, they are still referenced internally and will not be collected. As for the function you return, it really depends what it does. If you want to reference the instance and/or the table inside your function, you’re welcome to do so and they won’t be cleaned until they’re done with. For example:

local function something()
    local var = {}

    return function(val: string)
        table.insert(var, val)
    end
end

In this snippet, var will not be cleaned until all references are gone; this includes the returned function because it references var. So the GC goes, “hey this is still referenced in an alive object!” and doesn’t clean it. Only once the returned function goes out of scope will var be cleaned.


TL;DR:

  • Destroy instances and let the GC do the rest
1 Like

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