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.
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.
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.
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.
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.
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).