Weak Tables, Finalizers and Garbage Collection

20.1 Garbage Collection

Lua uses automatic memory management with an incremental mark-and-sweep collector. 5.4 adds a generational mode.

print(collectgarbage("count"))           -- memory in use (KB)
collectgarbage()                         -- full collection ("collect")
collectgarbage("step", 0)                -- perform an incremental step
collectgarbage("incremental", 200, 100)  -- 5.4: set pause and step multiplier
collectgarbage("generational")           -- 5.4: switch to generational mode
collectgarbage("stop"); collectgarbage("restart")
print(collectgarbage("isrunning"))

20.2 Weak Tables

Strings and numbers are values, not collectable objects for weak-table purposes: they're never removed from weak tables.

-- Weak keys: entries disappear when the key is no longer referenced elsewhere
local cache = setmetatable({}, {__mode = "k"})
local obj = {}
cache[obj] = "metadata"
obj = nil
collectgarbage()
for k, v in pairs(cache) do print(k, v) end    --> (empty)

-- Weak values: memoization caches that don't prevent collection
local memo = setmetatable({}, {__mode = "v"})

-- Ephemeron tables (weak keys, strong values) avoid key-value cycles keeping keys alive (5.2+)
local properties = setmetatable({}, {__mode = "k"})
local function set_prop(o, name, value) properties[o] = properties[o] or {}; properties[o][name] = value end

20.3 Finalizers (__gc)

Finalizers run at an unspecified time. Prefer explicit cleanup (or <close> variables in 5.4) for deterministic resource release.

Objects can be "resurrected" by their finalizer. Finalizers run in reverse order of marking. Errors in finalizers generate warnings (5.4).

local Resource = {}
Resource.__index = Resource
Resource.__gc = function(self) print("finalizing " .. self.name) end
function Resource.new(name) return setmetatable({name = name}, Resource) end  -- __gc must be in the metatable when setmetatable is called

local r = Resource.new("temp")
r = nil
collectgarbage()                --> finalizing temp