Lua OOP Memory leaking with bots

Hey,

so I’m trying out OOP in Lua for the first time and I have realized that I will probably leak memory by the way I’m scripting this right now.

Code on a server:

local BotObject = BotSystem.CreateBot(“Noob”, 100, workspace, Vector3.new(0,0,0))

CreateBot function in a module:>

BotSystem.CreateBot = function(Name, Health, Parent, Position)
	local con
	local self = setmetatable({}, Class)
	self.Bot = Objects.Bot:Clone()
	self.Bot.Name = Name
	self.Bot.Humanoid.MaxHealth = Health or 100
	self.Bot.Humanoid.Health = Health or 100
	if Parent then self.Bot.Parent = Parent end
	if Position then self.Bot:MoveTo(Position) end
	con = self.Bot.Humanoid.Died:Connect(function()
		con:Disconnect()
		wait(1)
		self.Bot:Destroy()
		setmetatable(self, nil)
		self = nil
	end)
	return self
end

How would I have to change things to not leak memory and to make it as efficient as possible?
After the bot dies the the table still exist and I want the bot to be completley removed.

Any help is appreciated!

Not sure if that would memory leak.
You could check by creating hundreds of the object and then checking the memory / performance tab.

I tried killing the bot, wait a few seconds and then print out the contents of the table. It prints out “Bot Noob”

I don’t think setting the metatable to nil helps. And setting self to nil doesn’t do anything either, since it only exists within the given scope anyway.

As long as the bot is no longer referenced anywhere, I think you should be fine.

Even if the bot ends up getting destroyed outside of its health hitting 0, that will still disconnect the con event automatically.

3 Likes

It’s doing that because you’re keeping a reference of it.

It’s kinda like the heisenberg uncertainty principle (not really): By “observing” the bot (keeping reference of it), it doesn’t get garbage collected. But if you stopped observing it, it would get cleaned up.

8 Likes

Yes, that’s what I thought. Should’ve tested it a little more. Thanks!

If you want to check if something’s garbage collected, you can hold a weak reference to it in a table and check the length of the table. For example:

-- utility function
local function getGcChecker(object)
	local gcChecker = setmetatable({object}, {__mode = 'v'})  -- let [v]alues be collected by the garbage collector
	return function()
		return #gcChecker == 0
	end
end

-- example usage
local t = {}

local checker = getGcChecker(t)

t = nil  -- lose all references to t

print('collected:',checker())

wait(3)

print('collected:',checker())

-- prints:
-- collected: false
-- collected: true

By using a table with weak table references – and by checking the length in order to never reference the object itself – you can observe if the object exists without actually observing the object.

9 Likes