Skip to content

Lua Garbage Collection

Lua features automatic memory management, primarily through a garbage collector (GC). This means developers generally do not need to manually allocate and deallocate memory for most Lua objects.

  • You don’t need to explicitly allocate memory for objects like tables, functions, strings, etc.; Lua handles this when they are created.
  • You don’t need to explicitly free memory for objects when they are no longer needed. The garbage collector identifies and reclaims memory from objects that are no longer accessible by the program.

Lua employs an incremental mark-and-sweep garbage collector. Periodically, the GC runs to find ‘dead’ objects – those that can no longer be reached from any part of the running Lua program (e.g., from global variables, the stack, or registers). Once identified, the memory occupied by these dead objects is reclaimed and made available for future allocations.

All Lua objects (tables, functions, userdata, threads, strings) are subject to garbage collection. The GC’s operation is controlled by two main parameters:

This parameter controls how long the garbage collector waits before starting a new collection cycle after the previous one finishes. It’s expressed as a percentage. A value of 100 (default is typically 200 in collectgarbage("setpause", GCTHRESHOLD)) means the collector waits until the total memory in use doubles before initiating a new cycle. Lower values make the GC more aggressive (running more frequently), while higher values make it less aggressive (running less frequently, potentially allowing more garbage to accumulate between cycles). The default value is 200.

Garbage Collector Step Multiplier (setstepmul)

Section titled “Garbage Collector Step Multiplier (setstepmul)”

This parameter controls the relative speed of the garbage collector compared to memory allocation. It influences how much work the GC does in each incremental step. Larger values make the GC more aggressive and complete its work faster relative to allocations. Smaller values (less than 100) might prevent the GC from completing a cycle if memory is allocated very rapidly. The default value is 200.

Controlling the Garbage Collector (collectgarbage)

Section titled “Controlling the Garbage Collector (collectgarbage)”

Lua provides the collectgarbage(opt [, arg]) function to interact with and control the garbage collector:

  • collectgarbage("collect"): Performs a full garbage collection cycle. Useful if you know a good time to reclaim memory (e.g., during a game level change).
  • collectgarbage("count"): Returns the total memory in use by Lua in kilobytes (as a floating-point number).
  • collectgarbage("stop"): Stops the garbage collector. Useful only in specific scenarios and should be used with caution, as memory will no longer be automatically reclaimed.
  • collectgarbage("restart"): Restarts the garbage collector if it was previously stopped.
  • collectgarbage("setpause", percentage): Sets the garbage collector pause value. arg is a percentage (e.g., 200 for 200%). Returns the previous value.
  • collectgarbage("setstepmul", percentage): Sets the garbage collector step multiplier. arg is a percentage (e.g., 200 for 200%). Returns the previous value.
  • collectgarbage("step" [, stepsize_kb]): Performs a single step of garbage collection. The optional stepsize_kb argument influences how much work is done (implementation-dependent). Returns true if the step finished a collection cycle.
  • collectgarbage("isrunning"): Returns a boolean indicating whether the collector is running (not stopped).
  • collectgarbage("generational"): (Lua 5.4+) Changes GC mode to generational. Requires arg to be "generational".
  • collectgarbage("incremental"): (Lua 5.4+) Changes GC mode to incremental. Requires arg to be "incremental", with optional arguments for pause, step multiplier, and step size.
local initial_memory = collectgarbage("count")
print(string.format("Initial memory usage: %.2f KB", initial_memory))
-- Create some garbage
local large_table = {}
for i = 1, 10000 do
large_table[i] = "Some string data #" .. i
end
local memory_after_allocation = collectgarbage("count")
print(string.format("Memory after allocation: %.2f KB", memory_after_allocation))
-- Make the table unreachable
large_table = nil
local memory_after_nil = collectgarbage("count")
print(string.format("Memory after setting to nil (before GC): %.2f KB", memory_after_nil))
-- Force garbage collection
collectgarbage("collect")
local memory_after_gc = collectgarbage("count")
print(string.format("Memory after explicit GC: %.2f KB", memory_after_gc))

The output of this program will vary depending on the Lua version, operating system, and the exact state of the Lua environment. However, you should generally observe an increase in memory after allocation and a decrease after collectgarbage("collect") (provided significant garbage was actually collected).

Example Output (illustrative):

Initial memory usage: 20.50 KB
Memory after allocation: 750.80 KB
Memory after setting to nil (before GC): 750.85 KB
Memory after explicit GC: 22.10 KB

While manual control via collectgarbage is available, Lua’s GC is generally efficient enough for most applications without explicit tuning. However, understanding these controls can be beneficial for performance-critical applications or when debugging memory-related issues. For most Lua programmers, simply setting unneeded variables to nil is sufficient to allow the GC to do its job.

Note on Weak Tables: Lua also supports weak tables, where references held by the table do not prevent objects from being garbage collected. This is an advanced topic useful for caches or associating data with objects without creating strong references.