What is physics/step in server memory and why is it so high?

I am developing a mining game with a few other people and just recently encountered a massive lag problem out of nowhere, seemingly overnight. After checking the developer console, I noticed that “physics/step” was higher than ever.


What is it and what could be causing it to rise so much? The game has very few unanchored parts, but spawns a lot of anchored parts as part of the mining system. This has never been a problem until now.

Hello.
Well after analyzing your situation, I remembered that I had a similar situation a while ago. All I did in order to solve it, is to reduce most server scripts files in one, and add a small wait() after a part spawns in the map. I would also recommend adding some optimization to your game such as :

  • Analyzing your code, and check for bad portions of code
  • Reduce script files’ number
  • Remove any unwanted instances
    I hope that will help you fix your problems.

This problem exists even when no parts are being spawned. As soon as a server opens, it jumps to 522MB and never changes. Parts are spawned as the mine when the game starts, but that shouldn’t be a permanent increase.

There is something that uses a lot of memory, check if you don’t have any virus script and try not declaring too many variables. In this case the solution would be looking in your code and your game’s files to detect what uses so much memory.

I finally found the problem and fixed it, it was actually something unusual.
In the base load system for this game, there were variables that referenced what block to spawn and some information about the block, all of which were objects. They were referencing objects over and over again without dereferencing them, thus the memory leak. By setting the variables to nil at the end of the loops I was able to completely get rid of it.
Why is this so weird? I thought this type of garbage collection was automated due to the scope, right? If you create a local variable that references an object inside of a loop that runs once, while existing inside a short function that runs once, it should know that those variables will never be used again because the thread ended. This isn’t the case.

5 Likes

The problem may be related to your function. It references variables externally, so if it’s placed in a table within a module it will never GC. Thus, any variables it references will also never GC.

Some things to note:

  • Module returns cannot really be GCed
  • Tables hold references to their keys and values
  • Functions hold references to any variables used
1 Like

This is not a module and everything is declared in the function, including tables. Everything should have ended inside the function right?

If the function is still referenced nothing it references will ever GC. If you hold a reference to the function in globals, in another script, or in a table somewhere it will always hold a reference. Is the function a global function? If so try making it a local function and see if this fixes the behaviour you’re getting. Where exactly is the function stored/called? My only explanation is that there is in fact still somehow a reference to the function which would mean the variables created within it would never be GCed.

This is my assumption of how your function is currently layed out:

function loadStuff()
    local someVariables = {}
    -- Stuff
    someVariables = nil
end

Is this correct? If so I believe what’s happening is the variables within your function never get GCed because the function somehow holds a reference to them, and due to it existing in the global environment it will be there as long as the script exists.

Wait, so when clearing tables you can’t just set the table to nil but you have to loop through and clean everything up? What is it’s subtables?

function loadStuff()
local someVariables = {
anotherone = {}
}

someVariables.anotherone = nil
end

Does this mean that the references inside anotherone are not GC?

Also does this only apply to global functions?

I normally write these:

local function functionname()

end

local module = {
randomFunction = function()

end
}

module.FunctionName = function)(

end

Would any of these be considered global?

You don’t have to cleanup subtables and values within tables, as the top table basically holds a reference to each of its values. You can however, ensure that no references are held using the __mode metamethod.

If it contains k, keys are weak. If it contains v, values are weak. Weak references essentially do not hold references which block GC to their values, however they can still be accessed. You can for example have __mode equal to kv to ensure both keys and values are weak.

As a sort of “best practice” I tend to always set the __mode metamethod of any tables I use excluding modules.

None of the functions/values you have listed there would be considered global since they aren’t defined on the global environment. I tend to find that global variables become a bit iffy on their GC behavior to be honest, but you would not have any issues there.

It’s a function that runs through just like that, would making it local change anything? It’s scope is entire script either way. It does not return anything either.

Making it local does not place it within the global environment, which behaves differently than a local, which is specific to the context. Here’s an example of what the function’s hierarchy could look like globally vs locally:

  • Script thread
    • Script environment - Essentially this is linked with the script thread in a sense
      • Global function - This is defined within the environment
    • Local context - This is sort of now its own context separate from the script’s environment
      • Local function - This is local to its own context

You can think of the local context as something completely separate from the script’s global environment. This works the same for “sub contexts” like in the below code:

local var1 = "123"
do
    local var2 = "abc"
    -- Another context
end
do
    local var3 = "456"
    -- Separate from the previous context, but part of the scripts' context
end

This may not be 100% accurate, but this is how I view things and as far as I know this is basically how it works. The global environment is its own table, and its the function environment of the script thread, therefore the global environment can hold references if it itself is somehow referenced internally.

(Sorry accidentally marked as solution)
I already knew that, but the function is at the top of the script so making it local won’t change much. I’ll try changing it though and comparing the memory when I can.

Making it local does not place it in the global environment. Having it in the global environment could hold a reference for longer, unlike locals. This is purely due to the fact that the global environment is a table itself. I believe that the global environment is held with the thread, which as I noted above, is extremely hard to GC. You should try making your function local.

I found the offender, it totally flew over my head. When loading players’ saves, I make a variable of their whole data table, which can be absolutely huge. This was never being dereferenced; it’s doing much better now.