Trying to understand memory leaks here

Memory leaks, in my opinion, are so complicated to understand. After reading a few articles, I still have some doubts regarding the knowledge I’ve absorbed.

Say I have a script like below:

local con = workspace.Baseplate.Touched:Connect(function()
    …
end)
con:Disconnect

and this is literally the entire code.

Does this cause memory leak? I’m having conflicting thoughts about it, yes because con still has a reference to the script connection despite it has been :Disconnected, no because when the thread ends (or when the scope ends), con is no longer used and therefore will be GC’ed.

Thanks.

1 Like

Very horrifying thoughts indeed.

I’m going to say no here.

When you disconnect the signal, the function no longer has any active script connections and should be GC’d.

Looking at this from an engineering standpoint, it also wouldn’t make sense to keep the function in memory after having disconnected it. So, assuming the engine’s design in this aspect is logical, no, this would not be a memory leak. I hope. Someone please provide more insight im scared.

Edit: Also, that would be assuming that the thread is still kept alive for some reason, such as the script having other tasks or there being a loop somewhere. If your code snippet is truly all there is, then no. The thread would close after the disconnection and everything in use by it would be GC’d.

1 Like

This isn’t regarding your memory leak predicament but my question is why dd you do it that way

when I do similar things I disconnect within the Event. like so

local con = workspace.Baseplate.Touched:Connect(function()
-- what ever I wanted it to do...
con:Disconnect()
end)

having the disconnect where it was would cause practically nothing to happen… you created and connected a function and then removed it all in one go… on purpose?

I am trying to understand the basics of memory leaks first, so I need to provide an easy code snippet for everyone to understand and clear my doubts. That’s why I made the script like so. I need clarifications on whether or not this caused memory leak and why.

1 Like

Memory leak occurs when something is not properly removed from memory, and ends up staying in memory. You can think of it like putting a box in a storage container, but forgetting to take it out after adding more things inside.

If they are not properly handled, it can otherwise lag, or slow down your game.

For the most part, connections by themselves do nothing, and wouldn’t cause that much harm, and if the Instance they’re attached to is removed, it will be garbage collected where all referenced to said Instance are removed.
One event that isnt properly disposed off is negligable, however that doesnt mean it doesn’t occur, in which I can add up. where thery can begin to do harm.

To prevent them, make sure you are properly disconnecting them using :Disconnect() and removing any references by setting the declared variable to nil.

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