Skip to content
AgileLogics
5 min read

Weak Tables and Garbage Collection

Prerequisites: Metatables and metamethods

Lua manages memory automatically with a garbage collector (GC): values that nothing refers to any more are freed.

local before = collectgarbage("count")
do
  local big = {}
  for i = 1, 100000 do big[i] = i end
end
local during = collectgarbage("count")
collectgarbage()
local after = collectgarbage("count")
print(during > before, after < during)
true	true

collectgarbage("count") returns memory in use (in KB); collectgarbage() runs a full collection. Lua 5.4 also offers a generational mode (collectgarbage("generational")), often faster for programs that create many short-lived objects.

Weak tables

A normal table keeps its keys and values alive. A weak table doesn't: if the only reference to an object is from a weak table, the GC can collect it.

local cache = setmetatable({}, {__mode = "k"})   -- weak keys

local obj1, obj2 = {}, {}
cache[obj1] = "data for obj1"
cache[obj2] = "data for obj2"

obj1 = nil
collectgarbage()

local count = 0
for _ in pairs(cache) do count = count + 1 end
print(count)
1
  • __mode = "k" — weak keys; "v" — weak values; "kv" — both.
  • Weak-keyed tables attach extra data to objects without keeping them alive — ideal for caches and per-object metadata.

Finalizers

local Resource = {}
Resource.__gc = function(r) print("releasing " .. r.name) end

do
  local r = setmetatable({name = "texture"}, Resource)
end
collectgarbage()
print("after collect")
releasing texture
after collect

A __gc metamethod runs when the object is collected — but when that happens isn't predictable. For files, sockets, and locks, release resources explicitly or with a <close> variable (Lua 5.4), and treat __gc as a safety net.