Best way to remove unused tables(Garbage Collection)?

So I have this class Chess Engine that creates a board that have all of the functions that generate the moves, make move, undo move and etc.; I want to clear the table once its game over, I made a simple set table to nil function that loop the table and check if value is a table then call the function again, in other words its recursion.

This is what the function looks like:

function ChessEngine:GameOver()
	setmetatable(self, {__mode = "kv"})

	local function convertTableToNil(table)
		for key, value in pairs(table) do
			if (typeof(value) == "table") then
				convertTableToNil(value)
			else
				table[key] = nil
			end
		end
	end

	convertTableToNil(self)
end

I’m not sure if this is the right way of removing unused table.

1 Like

Is this what you’re looking for?

for i in pairs(table) do
    table.remove(table, i)
end

table.clear should suffice.

Or,

for k in yourTable do
    yourTable[k] = nil
end

Edit: Why do you need to recursively clear the tables?

1 Like

Note: table.remove only works for arrays/numerical indices.

The Table Library has one function you may find that will suit your needs. That function is table.clear. It clears the entries in the table leaving it empty.

Some people have mentioned table.remove, but that only works on single entries in a table, which doesn’t seem to be what you want.

3 Likes

The first variable for in pairs is a number

Not necessarily; it can be anything depending on what the indices/keys of the table are.

To have no memory leaks/lessen the memory leaks on servers.

function ChessEngine:GameOver()
	setmetatable(self, {__mode = "kv"})

	local function convertTableToNil(currentTable : {})
		for key, value in pairs(currentTable) do
			if (typeof(value) == "table") then
				convertTableToNil(value)
			elseif (typeof(value) == "Instance") then
				value:Destroy()
			end

			currentTable[key] = nil
		end

		table.clear(currentTable)
	end

	convertTableToNil(self)
end

I still use recursion just in case that the values that are also a table would be wiped clean; in other words currently every variables on the table is a strong reference, after the convertTableToNil() function the __mode sets the "k"(key) or "v"(value) to weak reference. I use recursion to lessen the data of the table.

2 Likes

If you want to removed unused tables you can use table.remove and then supply the table you want to remove

Huh? That’s not how table.remove works.

table.remove removes an item from an array.

yourTable = nil should delete the table.

1 Like

An object (table, userdata etc.) with no ‘strong’ references to it will be marked for garbage collection during the ‘mark’ phase/step of a garbage collection cycle, an object that is marked will be swept and its allocated memory will be reclaimed by the application/program during the ‘sweep’ phase/step of a garbage collection cycle. This behavior means that objects do not need to be recursively cleared in order to reclaim memory allocated to nested objects.

local OuterTable = {
	InnerTable = {
		Constant = math.pi
	}
}

OuterTable = nil --Object and nested objects are garbage collected.
local InnerTable = {
	Constant = math.pi
}

local OuterTable = {
	InnerTable = InnerTable
}

OuterTable = nil --Nested object isn't garbage collected as a 'strong' reference still exists for it.
InnerTable = nil --Object will now be garbage collected during the next cycle.
4 Likes

I see; although this is a metatable and I want the table to be cleared with a method like :Destroy() or :GameOver(), setting the self = nil does not really clear the table:

-- Module Script
function ChessEngine:GameOver()
	self = nil
end
-- Main Script
ChessEngine:GameOver()

print(ChessEngine) -- still prints it's content {...}

That’s why I used recursion to set its content to nil so when I call :GameOver() it returns an emplty table {}, also setting its __mode = "kv" make’s the key and value to weak reference, and I’m wondering if that also applies to the tables inside.

local Object = {}

function Object.new()
	return setmetatable({}, {__index = Object})
end

function Object:Destroy()
	self = nil --Self is a new reference to the object.
end

local NewObject = Object.new()
NewObject:Destroy()
print(NewObject) --Memory address of object.
NewObject = nil --Need to explicitly set the variable to nil in order for the object to be garbage collected.
print(NewObject) --'nil', object is garbage collected during next cycle.

‘self’ is just a reference to the object.

Yeah that’s why I used recursion to clear the table.

This is just an example.

From a quick glance that implementation looks fine, you may want to add ‘s’ to the __mode string in order to mark the weak table as ‘shrinkable’ (garbage collection optimization).

Check the 4th paragraph of the linked section.

2 Likes