Trying to understand memory leaks here

So I am assuming, the code snippet I have provided, will cause a memory leak because even though the Touched connection is disconnected, there is still a reference to the connection which is the variable con, because con was never set to nil?

Memory leaks really only occur in languages such as C, which allow for manual memory allocation. Lua (and roblox’s Luau) most certainly cannot leak seeing as how it doesn’t even have support for pointers or manual memory allocation.

The only way you could possibly witness a memory leak is if luau is causing it, not you.

For more information about memory leaks: Memory leak - Wikipedia

The reference will still exist, therefore it wont be garbage collected until it is properly removed like with every Instance.

print(con.Connected) -- should print 'true' as its connected
con:Disconnect() -- disconnect event
print(con.Connected) -- should print 'false' as its disconnected
con = nil -- remove reference
print(con) -- gone, will be garbage collected if no more references exist.

For functions like :Destroy(), it will do that for you, however :Remove() will not.

No. Luau automatically does garbage collection and will set it to nil automatically.

Realistically, you don’t ever have to worry about memory allocation. Luau automatically does that for you.

@DasKairo @egginabox0

Both of you have conflicting answers. So which one is correct? If @DasKairo answer is correct, then that means I literally need to set every variable to nil if they’re no longer being used.

But if @egginabox0 is correct, then how does it know when the variable is no longer used? When the thread is finished executing? When the scope ends?

Garbage Collection and Memory Leaks in Roblox - What you should know - Resources / Community Tutorials - Developer Forum | Roblox

Try reading this.

TL;DR: Luau does garbage collection. Automatically. It depends on a few things, like scope, and whether or not a thread is alive.

  • Things like wait() will prevent a threat from terminating until the thread finishes waiting.
  • Scope is important: exiting a level of scope will mean that garbage collection can occur to memory in that scope.

Unreadable memory is (to my knowledge) impossible.

1 Like

I’ve read that, so if my entire script is just like that, then it won’t cause a memory leak because the script/thread has ended, therefore it will be GC’ed?

Correct. Once a thread finishes doing its thing it will be GC’ed.

  • One exception: when :Connect() is called, you’ll need to call :Disconnect to tell luau that its ok to GC. It won’t GC even if the script stops running. It’s best to call :Disconnect when you’re not using that listener anymore anyways.
2 Likes

@DasKairo

What’s your verdict? Do you agree with him?

He’s correct. When you call :Disconnect, and there’s nothing else utilizing the thread such as a loop that’s still running or another connection, the thread dies and everything in use by it is GC’d.

Edit: This was the initial answer I should have given. I was thinking about it from the perspective of the thread still being active, but after I re-read your question and the snippet you gave, I edited my post.

3 Likes

Lua doesnt do this, it instead garbage collects whatever exists in memory that does not have any references (being Variables, or an index in a table)
If you’re refering to things running without a reference, then this would be true.

Any language can have a memory leak of some kind.

With most languages, they will have a way for them to automatically manage memory (usually being to remove items with no references such as Lua/Luau).
C is unique in the fact that it does not have this, in which the progammers using the langauge have to manually manage their memory.

In C, you are more likely to experience memory leaks from memory you dont properly manage, which in some cases is more efficient than automatic garbage collection if done correctly.

In Lua, the same thing can occur, however Lua is a language that can automatically dispose of memory that isnt referenced anywhere, in which if a reference still exists, wont be cleared from memory until said referece is gone or otherwise “dead”.

Its the same problem, but with different solution as to how things are being disposed of.

Mostly.

While the thread is garbage collected, the Connection isnt unless the Instance containing said connections is removed, or disonnected and set to nil. The Connection (or RBXScriptConnection) itself is an Instance that also takes up memory in some form.

In general, its just a better idea to dispose of what you’re not using anymore, or to otherwise save it for later if something else is going to be using the same information.

So, does that mean I literally have to set the variable to nil so the GC can fully GC it? Then it would contradict what @egginabox0 said:

As mentioned:

The connection will spawn a thread that is ran and then garbage collected once finished. The connection itself is an Instance that you bind a function to run, thats what you have to remove in order for it to be garbage collected, otherwise the Instance will stay in memory due to the variable still referencing it.

Whenever you use :Connect(), it creates a RBXScriptConnection, without a variable you wont be able to reference it to disconnect it, so in order to “kill” it, you have to remove what its connected to, which in turn disconnects the connection, and because it has no reference, it can be garbage collected.
As opposed to if you’re referencing it in a variable, you can easily manage it, and dispose of it whenever you feel like it.

Edit: Iirc you can also “kill” it, if the script is no longer runs, but thats something I need to verify later.

The script connection only generates a thread when the event is called, no? If the connection itself was its own thread, then each event call wouldn’t run in its own scope, but it does. It’s not its own thread with a function wrapped in it, similar to what coroutine is. It spawns the provided function each time the event it’s connected to is fired.

1 Like

This is exactly what I said:

If you need more clarification:

local con = workspace.Baseplate.Touched:Connect(something) -- creates an Instance
-- whenever the connection is called, it will create a thread
-- the thread itself will be collected while the connection persists
con:Disconnect() -- you disconnect it
-- no more threads being made out of this
-- 'con' is still referencing a "Dead" Instance
con = nil -- remove the dead Instance for it to garbage collect said instance

Right, so, the connection itself doesn’t generate its own thread, it’s part of the thread is was created in. So when the thread it was created in dies and the connection is disconnected, the connection itself should be GC’d as well.

Either way, I’m about to find out. I’m going to create a connection in a thread and terminate it, comparing with a coroutine. I’ll report findings.

1 Like

So you’re basically disagreeing with @egginabox0 answer, that is, when the connection is disconnected, it won’t be automatically garbage collected until con is set to nil to remove all references to the connection.

Which is going to be annoying because that means I have to set every variable to nil when I’m not using them anymore.

This is getting even more confusing, so how would I prevent memory leaks? Do I need to manually set all no longer used variables to nil? Or does the garbage collector handles it by itself?

You’re not exactly understanding what im saying.

The Connection is Disconnected, there wont be anymore threads, in which whatever is ran, will be garbage collected.
This only works if you destroy the Instance from which the connection is referencing are removed.

The function you are looking at with that feature is :Destroy(), as it removes itself from the reference so it can get garbage collected, which the connection does not have, meaning you’re required to do what I said:

If you talking about what the connection is firing, thats garbage collected, no need to worry about it.

If you’re talking about what its firing from, you have to manually diconnect it and remove it from the variable, or remove what its connected to. By diconnecting the connection, you prevented the memory leak, the last thing you need to do is dispose of the connection so that piece of information isn’t kept, so it also doesnt cause a memory leak.

Im not sure how I can explain this better, or make it less confusing, thats kind of my fault tbh.


He’s right, im not disagreeing with that, but there is an extra step to what needs to be done in order to dispose of the item.

Perhaps I didn’t give a clear example, so here’s another example:

Let’s say I have a lot of variables, and I won’t be needing all these variables once I am done using them.

The question is, do I need to set them to nil so that the garbage collector can collect it?

It really depends on whats there, i’ll try to explain.

If you have a group of Parts you can to remove, you can use the :Destroy() function, which sets the variable to nil, and the Parts are now gone from memory.

As for Connections, it doesnt have a :Destroy() function, because of that, you have to do it manually by setting it to nil.
So whenever something is being collected or checking to be collected, it checks if the object is “Dead” or “alive”, if its dead remove it, if its alive dont do anything to it. The connections Killswitch is :Disconnect(), and Boom, its Dead, so you now you dispose of it from the variable, and boom its now being garbage collected.

If you wanted to do the exact same process but with a Part, you just set its Parent to nil, then you set the variable to nil, you would be doing the exact same thing as you are with the connection, and :Destroy()


To make the process more managable, i generally just recommend adding them into a table, so a simple for loop can easily dispose of the objects.

local cons = {} -- a table
table.insert(cons, Part.Touched:Connect(function() print("e") end))
-- whatever amount of connections you want to add

for i,con in cons do -- loop through table
    con:Disconnect(); -- disconnect connection
    cons[i] = nil; -- dispose of connection
end

I also helps with organization, and I generally use it whenever im messing around with Players, such as connections like CharacterAdded, or Died, so im able to properly dispose of them.

Basically, its just one extra step to dispose of the object. Thats probably the best i can explain it.

1 Like