Performance Optimization
Use locals: local variable access is a register operation. Globals and table fields need lookups. Cache hot functions: local insert, floor = table.insert, math.floor.
Avoid creating garbage in hot paths: reuse tables, avoid closures and string concatenation inside loops, and use table.concat for strings.
Preallocate tables: constructors like {nil, nil, nil} or table.new(narr, nrec) (LuaJIT) avoid rehashing.
Prefer numeric for over ipairs in very hot code. Use t[#t + 1] = v instead of table.insert(t, v) (avoids a function call).
Avoid #t repeatedly in loops: cache the length (# is O(log n) for tables).
String operations: string interning makes equality fast, but creating strings costs. Use string.byte / string.find with plain = true when possible. Precompute patterns.
Metamethods and __index chains add lookups. Flatten deep inheritance for hot objects, or cache methods in locals.
GC tuning: use generational mode (5.4) for allocation-heavy workloads, adjust pause/step multipliers, and run incremental steps during idle frames (games).
LuaJIT: keep code JIT-friendly (avoid NYI functions in hot traces), use FFI arrays/structs for numeric data, and avoid polymorphic code in hot loops.
Algorithmic wins first: use sets/lookup tables instead of linear searches, and memoize expensive functions.
Move hot spots to C via the C API or LuaJIT FFI when profiling shows they matter.
-- Before
for i = 1, #data do
result = result .. tostring(math.floor(data[i]))
end
-- After
local floor, parts = math.floor, {}
for i = 1, #data do parts[i] = floor(data[i]) end
local result = table.concat(parts)