Scripts running in nil

I’m pretty sure that scripts were supposed to stop running when :Destroy()ed or parented to nil. Am I comepletely mistaken, or is this the desired behavior?

For reference, just set a script’s parent to nil or destroy it on the first line. All the following code executes.

this applies to both local and server scripts
1 Like

Parent to nil is intentional.

All Destroying does is parent the object to nil (and locking parent to nil) and disconnect everything so the garbage collector can deal with it.

So I’m like 95% sure destroy is intentional as well.

4 Likes

Some devs parent scripts to nil on purpose as a tactic for exploit prevention. So changing this to a thing that disabled/destroys the script would probably break a ton of games out there.

6 Likes

That is so cool, I thought of it but never tried it before.

Although I thought a Script would Run again after it’s reparented?

So the best way to get rid of a Script is to Destroy it and also Disable it?

Also does the “Garbage Collector” remove the Deleted Object from the game completely or it just stays in Nil?

script:Destroy()
while wait(1) do
	print(workspace.DistributedGameTime)
end

This Script will run forever… so How do we get rid of the Script Completely?

https://www.lua.org/manual/5.1/manual.html#2.10

The garbage collector (from what I understand) is made to clean up variables and objects (including roblox userdatas) that aren’t accessible from within Lua anymore from memory. With that in mind, it probably wont touch your scripts in nil since they’re actively running.

do
    local lol = true -- lol only exists within the memory of this do block. If you try to access it outside the block, it doesn't exist.
end
-- The garbage collector will clear lol from memory once all the code is run.

I see.

So our Functions are stored in the memory right?

And other Variables, Tables

So If I did this

local HeheXD = true

wait(1)

HeheXD = nil

So HeheXD will be removed from the memory because I set it to nil?

1 Like

Mhm. Although it should be noted that the lua garbage collector isn’t actively running. As in, it may take some time for HeheXD to actually be removed from memory, after being set to nil. You can prompt it run a cycle anytime though with collectgarbage().

Parenting a script to nil is not very useful as exploit prevention tactic as the code is still available with some effort (exploiters can read it from nil). Also I think since stacktrace has to remain available and the scripts having possible references to non-Lua parts of the engine, it is too difficult to determine when code is entirely without references and gc-able, thus scripts are never gc’d as precaution. Correct me if I am wrong, @Rerumu

1 Like

Oh , I see that is useful information

The Wiki does not tell you any of that

Don’t forget that it is possible to leak memory on Roblox even with garbage collection:

do
    local part = Instance.new('Part')
    part.Touched:connect(function() print(part) end)
end

The above part will stick around in memory forever even though there is no way to access it, since the connected function has a reference to the part. That’s why actually Destroy’ing things is important vs just throwing them into nil, because Destroy will disconnect those connections that may leak references otherwise.

There are actually some VERY rare cases in which the scripts do get gc’d, but I’ve only been able to have this happen with one or two methods which really limit what it can do.

1 Like

Are you sure? IIRC Roblox does garbage collect objects if there’s no Lua thread holding a reference to it and the DataModel doesn’t have a hold on it. If there’s a script holding the connection in memory then it won’t be garbage collected, but in your case you aren’t keeping that connection in any scope.

EDIT: I see what you mean, but in this scenario it seems like it should be weakly connected, given the context of the signal. If the object has no way of being changed because it has been isolated from any strong references to the object, then it should be garbage collected? If it isn’t doing this, then it’s probably a bug that could be fixed.

Something which should be clarified:
This method of theft prevention only applies on the Server, and does not apply to the Client as you have no control over the physical Client itself. Sorry to burst bubbles, I just wanted to ensure no one tried this expecting to protect local source.

Afaik all Roblox connections are created equal. That seems like it should gc, but realize there still is an upvalue reference to it, which was CLOSE’d. It’s a bit ambiguous as to what it may actually do.

So… Does that mean if I set the own script’s reference to nil AND parent the script to nil, it’ll get gc’d?

By set the own script’s reference to nil I mean script = nil

No – a script is merely an object wrapping a Lua thread; it shouldn’t get gc’d from that, as the thread still needs to be handled internally.

1 Like