lua

Lua Variables And Its Effect On Speed And Memory


So if I understand this correctly, Lua data types of string, numbers are values, while functions and tables are references. Does this mean that if I do:

local x = 5
local y = x

Is the variable y, a copy of x and is not a reference, which means doing it this way will consume twice the memory?

While doing:

local myTab = { one = "hello" }
local myTab2 = myTab

Would mean that myTab and myTab2 reference the same table and assigning myTab to myTab2 won't consume extra memory?

I ask this since I usually tend to reassign global variables to local variables to improve speed.

Such as:

Config = {} -- This is in file1.lua

-- On file2. lua we do:

local Config = Config

So this should theoretically improve speed by a bit since we're assigning it to a local variable, but I wonder if doing so will consume significantly more memory, especially when we're dealing with larger programs with bigger data.


Solution

  • So if I understand this correctly, Lua data types of string, numbers are values, while functions and tables are references.

    Since your question is ultimately about implementation details (e.g. memory usage): It is a bit more nuanced than this.

    Lua values are effectively a "tagged union": There's the type tag, and then there is a value, usually one machine word. For types that don't fit into a single machine word, this value will be a reference, and these types will thus be "reference" types.

    nil, booleans, and numbers in Lua are "primitive" types: They are cheap to copy (they use up just a single machine word or less, maybe two machine words together with the type tag, if your Lua implementation does not use NaN boxing), so they are copied on every assignment. The value is just the boolean or floating-point number value. Not copying them (referencing them) would be more expensive than copying them.

    Strings behave like a "value" type: They are immutable, so there's no difference between copying and referencing them. But they are implemented as reference types for performance reasons nonetheless. If you assign a string to a variable, the string isn't being "copied" - only the reference (a pointer with a type tag) is being copied.

    This means that when you do local x = ..., you are only using a constant amount of extra memory: The extra memory needed to store one Lua value, which will be around one or two machine words. There is no copy of tables, strings, userdata, threads or functions happening here: All types that aren't trivially copyable are implemented as reference types, mutable or not.

    So this should theoretically improve speed by a bit since we're assigning it to a local variable

    Indeed it usually does, since it saves you a hash lookup in the global table, but I would recommend against premature optimization nonetheless, especially considering "smart" implementations like LuaJIT.

    but I wonder if doing so will consume significantly more memory

    Usually not significantly, but you might want to be aware of the following ramifications:

    So this is ultimately a time-space tradeoff: If you don't localize, functions have to hit the global table (technically their environment table, which defaults to the global table) to get at global variables. If you localize, you're marrying the function to the values at the time you localize, at a small memory cost (because the function now effectively needs to store a pointer to the upvalue).

    Note also that localizing interferes with monkey-patching: Suppose you do Config = {frobnicate = true}, then load a file which localizes local Config = {}, then another file which redefines Config = {frobnicate = false}. The second file will still work with the outdated definition.