How to prevent this memory leak?

Hi, i’m working on making my own observer pattern module, but it’s not important, the important thing is that i need to run function in coroutine, and when it finishes, remove it from a table

function Connection:run()
    local thread
    thread = task.spawn(function()
        self.Callbakc()
        local index = table.find(self.Threads, thread)
        if index then
            table.remove(self.Threads, index)
        end
    end)

    table.insert(self.Threads, thread)
end

This is where problem starts, it causes memory leak because thread cannot be removed sometimes, and when it’s left in table, it stucks, any idea how to fix it or have something like that functionality?

task.spawn() will run the function immediately, so it will call self.Callback(). and if that callback is not yielding, then it will continue to find the thread in table. but at this point, the thread is not inserted.
after that, the thread is inserted

1 Like

How to prevent that? When i used coroutines yielding was cause of a problem, and here lack of it is the problem

try task.defer(). that will delay the function running and the table.insert should be called first.

1 Like

Thx, one more question, because when i used coroutines, and callback function yielded, it caused memory leak, do you know why?

could you post the code for that implementation please

1 Like
function __Thread:start(Callback, ...)
	self.Thread = task.defer(function(...)
		Callback(...)
		self:destroy()
	end, ...)
	
	if self.Connection then
		table.insert(self.Connection.Threads, self.Thread)
	end
end

If callback yields, it will cause memory leak

destroy methood:

function __Thread:destroy()
	if self.Connection then
		local ThreadIndex = table.find(self.Connection.Threads, self.Thread)
		if ThreadIndex then
			table.remove(self.Connection.Threads, ThreadIndex)
		end
		
		self.Connection = nil
	end
	
	if self.Thread then
		coroutine.yield(self.Thread)
		coroutine.close(self.Thread)
		self.Thread = nil
	end
	self.IsRunning = nil
	
	setmetatable(self, nil)
	table.freeze(self)
end

i think nothing to do with using coroutine or not,
self.Connection.Threads is a table, its intention is to hold multiple threads,
so we would assume we can call start() multiple times for different callbacks and then they’ll self clean up.
however, we only have ONE self.Thread , and then rely on that single entry to find itself. then all other threads are lost.

1 Like

It turns out, after a test, that it might not be memory leak but rather registry optimization, there is similar behvaior in tables, i tried running connection 100 times (and also run 100 threads) twice, registry only grew once, later it became stable

I’m afraid that this optimization might cause some issues in the future, but if threads will be used sparingly then it wouldn’t do that much, anyways thx for help