Module script memory

When requiring Module scripts, do they take up memory similar to variables and connections? If so, is there a way to delete this memory similar to setting a variable to nil or disconnecting a connection? Any help or idea is appreciated.

3 Likes

Yes, anything that exists in your game will take up memory.

The returned value from module scripts are cached, and are never removed from memory. You can test this yourself:

local m = require(script.ModuleScript)

local gcTest = setmetatable({m; {}}, { __mode = 'v' })

m = nil

while gcTest[2] do
	task.wait()
end

task.wait(1)

print(gcTest[1]) --> {} (not garbage collected)
print(gcTest[2]) --> nil (garbage collected)
2 Likes

Yeah they do, but it’s not something you need to worry about. Many games have tons of modules. Although personallly I don’t use them much, since my code is clean enough for me. So if you wanna save memory just make your code clean and use as least modules as possible unless you need em. For like a framework for example.

1 Like

What if the module script itself is deleted from the game? I have a system where the clients requires module scripts to play a specific animation, once that animation or module script is done or deleted, I want to wipe the module’s memory away. The module script itself contains a function which is played on the client when required.

To test if the module is still running even after the module has been deleted, I added a while loop with a print statement within it. I then required that module on a local script and when the module was deleted the printing was still happening. This makes sense as the function is ran on the local script and it’s a easy work around however, the memory is still there. Is there a way I can get rid of the memory?

1 Like

Yep, I am using module scripts for framework, in this particular case: client animations. While big games do use a lot of module scripts, I am using them as a way to play specific animations on the client. For example, when an item is dropped in my game, there will be a dropping animation played on each client which is provided via a module script. This means that the client will require many module scripts throughout time (for example, whenever the dropping animation needs to be played for a specific item or when a tree breaks), which is much more memory used in module scripts than the average game. My problem is that I am trying to delete the memory after the module is done running. Similar to a connection, the memory will stack up over time if I don’t find a way to get rid of this memory.

1 Like

There was a flaw in my gc testing code. It looks like destroyed required modules are garbage collected when there are no references to its cached value anymore

local ms = script.ModuleScript
local r = require(ms)

local gcTest = setmetatable({r; {}}, { __mode = 'v' })

r=nil
ms:Destroy()

while gcTest[2] do
	task.wait()
end

task.wait(1)

print(gcTest[1]) --> nil (garbage collected)
print(gcTest[2]) --> nil (garbage collected)

When the cached value is garbage collected, attempting to require the module again will result in an error.

1 Like

In theory, module scripts are basically just adding lines to your code. This means that if a function is played only once or if a while loop is broken then there should be no memory stored, since it’s not stored in a variable or connection or later use.

I don’t know how to check the memory of the sever accurately as it is unstable and just 1 module script won’t make too much of a dent in the memory however, in theory, if the function within the module is done playing, then memory should be deleted?

1 Like

It depends. Do you still have a reference to whatever the module returned (be it a variable, a member in a table, etc)? If you do, then it won’t be garbage collected. You can use the code above to check whether something specific was garbage collected (freed from memory)

1 Like

I just ran a few tests, it looks like everything works if the function had no loop inside it however, I tried to put this piece of code into my module script:

local function module()
local BreakTime = os.time() + 10
while task.wait() do
print(“in loop”)
if BreakTime <= os.time() then
break
end
end
end
return module

and I added a “r()” on top of the r=nil in your code to play the function and it seems like it did not garbage collected “gcTest[1]”, or the function itself after the function was done playing

A module isn’t an independent script, it is only an expansion of the script.

In a short and easy understandable explanation, modules scripts are a storage of code, which mean the code inside them never run, the code run inside the script that required the module.

Requiring a module is like copying the code inside it (the table), and paste it into the script to run it.

So yeah, it take additional memory when you require them as you copy-paste the code into the script… It is also why they aren’t shown into the console, because the memory it take is added to the script memory, the one that required the module.


Doing this:

local Module = require...

Is exactly same as doing this:

local Module = {
    VariableName = ...;
    FunctionName = function()
        --code
    end;
}

It wont do anything apart make you unable to require it again, another time, the module script itself do not run code, the code is runned by the script that required the module.

So if you want to stop it, you have to disconnect connections inside the script and set the module variable to nil to destroy the copy of the module table into your script.

local Module = require(...)

--Do a module function to disconnect all connections
Module:DisconnectThings()

--OR disconnect all connections from there
Module.ConnectionFunction:Disconnect()

--Then, set it to nil to destroy the table and everything it contain
Module = nil

Thank you to everyone that responded, I’ll sum up everything mentioned in this post for anyone in the future wondering about Module script memory:

To Start, requiring a Module script is basically like adding its lines of code to a script, for example:

Module script’s memory is created when we require it, and will be destroyed when there is no longer a way to reference it, for example:

local Module = require(TheModule) -- memory is created
Module = nil -- memory is destroyed

Heads up: If there is any connections, variables or any memory still stored within the module script itself, remember to disconnect/nil them or it can cause a memory leak, for example:

To check if your memory has been destroyed, you can use this code right here:

2 Likes

Ill mark this as solution tomorrow, let me know if there is anything I should add

It is pretty much what i said in my answer lol

Also like i said in there

You need to disconnect all connections before setting it to nil, because destroying the Table won’t automatically disconnect connections, not doing it will cause memory leaks and a possible increase of performance issues by the time.

Example with a local script

script:SetAttribute("test", true)

local Module = {
	Connection = script:GetAttributeChangedSignal("test"):Connect(function()
		print("changed")
	end)
}

task.wait(1)
script:SetAttribute("test", false)
task.wait(1)
script:SetAttribute("test", true)
task.wait(1)

--Module.Connection:Disconnect() --test with and without it
Module = nil
print("destroyed")
print(Module)

task.wait(1)
script:SetAttribute("test", false)

thanks for the feedback! I updated my original post

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.