Lua - Weak Table



In Lua, developers are not required to delete or free memory as Lua provides automatic memory management via garbage collectors. A garbage collector is special entity which reclaims the memory of an object if there is no strong reference exists to that object.

Whenever we create a new table, an object is created and if two same tables are created and assigned to two references, eventually two objects are created occupying the memory. If we set one reference as nil, then garbage collector will reclaim the redundant object.

Problem statement

Now in case of a collection/table, where we're storing the objects directly as keys or values then garbage collector will not collect the objects even if those were not in use because table/collection is still referencing the objects. How to tell the garbage collector to reclaim memory of such object?
-- empty collection
days = { }

-- create a key as object
key = {}

-- set a value
days[key] = "mon"

-- create second key as object   
key = {}               

-- override the first key
days[key] = "MON"

-- forces a garbage collection cycle
-- to collect first key as it is not referenced now
-- but first key will not be part of reclamation cycle
collectgarbage()  

Solution

Weak table is the solution for above problem. A weak table is a mechanism provided by Lua to tell a garbage collector that references are weak. A weak table can have keys as weak references, values as weak references or both as weak references. A meta field __mode is used to mark keys, values or both as weak.

Set keys as weak Keys in a Weak Table

-- weak table
days = {}

-- meta table
modes = {}

-- set the metatable
setmetatable(days, modes)

-- set the keys of days tables as weak keys
modes.__mode = "k"    

Set values as weak values in a Weak Table

-- weak table
days = {}

-- meta table
modes = {}

-- set the metatable
setmetatable(days, modes)

-- set the values of days tables as weak values
modes.__mode = "v"    

Set both keys and values as weak in a Weak Table

-- weak table
days = {}

-- meta table
modes = {}

-- set the metatable
setmetatable(days, modes)

-- set the keys and values of days tables as weak
modes.__mode = "kv"    

Complete Example of a Weak Table

Following is a sample example, demonstrating use of weak table for memory management.

main.lua

-- weak table
days = {}
-- meta table
modes = {}
-- set the metatable
setmetatable(days, modes)

-- set the keys of days tables as weak keys
modes.__mode = "k"         

-- create first key as object
key = {}
-- set a value
days[key] = "mon"

-- create second key    
key = {}               

-- override the first key
days[key] = "MON"

-- forces a garbage collection cycle
-- to collect first key as it is not referenced now
collectgarbage()    

-- print the values in the table
for _, day in pairs(days) do 
    print(day) 
end   

Output

When we run the above code, we will get the following output−

MON

Key Points on Weak Tables

  • Only objects can be collected from a weak table.

  • Numbers, booleans like values are not collectible.

  • If a object, either key or value is collected from a weak table, complete entry is removed.

  • A String, although collectible is not removed from a weak table unless its associated value is collected.

Advertisements