so im trying to clear all my self variables in my class to clean up memory and optimize. i’m not really sure whether setting self to nil would clear all of its references in my clean up function `:Complete’.
i assume you have to clear all connections before removing all the references so i’ve done that just to make sure. i have also destroyed my gui buttons before clearing the table as well.
are you meant to set each self variable to nil on clean up like this?
function ClickTask.new(player, buttonTemplate)
local self = setmetatable({}, ClickTask)
self.player = player
self.buttonTemplate = buttonTemplate
self.buttons = {}
self.connections = {}
self.progress = 0
self.maxButtons = 5
return self
end
function ClickTask:Complete()
-- disconnecting any left over functions
for _, conn in ipairs(self.connections) do
if conn and conn.Connected then
conn:Disconnect()
end
end
-- delete the ClickTaskGui
if self.ClickTaskGui then
self.ClickTaskGui:Destroy()
end
self = nil
end
just use ECS bro.
ECS would let you clean up everything.
For now deleting metatable and in some cases table.clear() may work but as i said OOP is a joke commit some Entity Component System
function ClickTask:Complete()
-- disconnecting any left over functions
for _, conn in self.connections do
if conn and conn.Connected then
conn:Disconnect()
end
end
-- delete the ClickTaskGui
if self.ClickTaskGui then
self.ClickTaskGui:Destroy()
end
setmetatable(self,nil)
table.clear(self::{})
end
return function(player, buttonTemplate)
local self = {}
self.player = player
self.buttonTemplate = buttonTemplate
self.buttons = {}
self.connections = {}
self.progress = 0
self.maxButtons = 5
return setmetatable(self, ClickTask)
end
You don’t really need to set anything to nil inside the instantiated object. Just call destroy on anything it creates like associated instances or other classes, make sure connections are disconnected, and call it a day. Once all references to the object are lost, it will be automatically cleaned up by the garbage collector.
for example,
local function createAndDestroyMyObject()
local myObject = MyObjectClass.new()
myObject:destroy()
end
createAndDestroyMyObject()
In this function, the object is created, destroy is called, and then the reference to myObject goes out of scope and is lost forever, so it will get picked up by the garbage collector, assuming MyObjectClass’s destroy method correctly disconnects any active signal connections, destroys any instances it created, and calls destroy on any classes it created inside.
To further clarify, I do not need to set myObject = nil to “clean it up” in the same way that MyObjectClass.destroy does not need to set all the fields of the instantiated myObject to nil. The myObject table itself will be GC’d when there are no longer any references to it in memory.
This is a common misconception that I personally grappled with when I started using self.
What you did with ClickTask.Complete() is already good enough. You disconnected all events, and you also destroyed any instances you are not using anymore.
You do not need to set self = nil, as that’s redundant and doesn’t do anything. self is just a variable that has the value of the table you used the : (colon) operator on. Once you disconnect all events and there are no references to your metatable, the Lua gc will automatically clear the metatable from memory.
If that doesn’t make sense, you can think of it this way:
local function foo(thisIsAVariable: number)
local variablePlusOne = thisIsAVariable + 1
thisIsAVariable = nil --[[
setting this variable to nil does absolutely nothing
once this function completes its execution, "thisIsAVariable" will
automatically be garbage collected, since there will be no more
references to it
]]
end
I recommend creating your own cleanup methods like you have done, but some people prefer to use modules like Maid by Quenty. I think those are fine to use once you understand how they work, I think it’s a bad idea to just use them without understanding how garbage collection actually works..
thanks so much for your help! after reading a lot more about the garbage collection that post was very helpful for my situation.
from what i gathered, the garbage collector doesn’t clean up connections or instances so that’s what i cleaned up in my clean up function. i’m not sure whether you should clean up tweens and coroutines (that’s if u can actually do so) but yeah!
While I didn’t show how MyObjectClass is set up, it is quite normal practice to include a :destroy() method in the same way as including a .new() method. It’s not a built-in, it’s just something I define on all my classes to have a standardized way of calling a deconstructor.
At the risk of over-clarifying, I’ll provide the following example. Imagine MyObjectClass has a deconstructor that calls :destroy() on some other class it created in its constructor:
local SomeOtherClass = require(path.to.SomeOtherClass)
local MyObjectClass = {}
MyObjectClass.__index = MyObjectClass
export type ClassType = typeof(setmetatable(
{} :: {
_someProp: SomeOtherClass.ClassType,
},
MyObjectClass
))
function MyObjectClass.new(someValue: string)
local self = {
_someProp = SomeOtherClass.new(someValue),
}
setmetatable(self, MyObjectClass)
return self
end
function MyObjectClass.destroy(self: ClassType)
self._someProp:destroy()
end
return MyObjectClass
Notice how it’s not necessary to set self._someProp = nil in the deconstructor. As long as I call MyObjectClass:destroy() and then lose the reference to the instance of MyObjectClass, its internal reference to an instance of SomeOtherClass will also be cleaned up by the garbage collector. Having some standardized way of chaining deconstructors such as with a :destroy() method is useful.