Skip to content
Learni
View all tutorials
Développement

How to Optimize Performance with Lua in 2026

Lire en français

Introduction

Lua excels in embedded environments and games thanks to its lightweight nature. In 2026, performance demands require deep mastery of metatables, coroutines, and LuaJIT. This tutorial guides you step by step toward concrete, measurable optimizations.

Prerequisites

  • Lua 5.4 or LuaJIT 2.1+
  • Solid knowledge of tables and functions
  • C compiler for extensions
  • Benchmarking tool like bench.lua

Advanced Dynamic Metatables

metatable.lua
local mt = {
  __index = function(t, k)
    if k == "computed" then return t.base * 2 end
    return rawget(t, k)
  end,
  __newindex = function(t, k, v)
    if k == "locked" then error("Champ verrouillé") end
    rawset(t, k, v)
  end
}
local obj = setmetatable({base = 10}, mt)
print(obj.computed) -- 20

This metatable implements lazy computation and modification protection. It avoids infinite loops by using rawget/rawset.

Coroutines for Asynchronous Tasks

coroutine.lua
local co = coroutine.create(function()
  for i = 1, 3 do
    print("Étape", i)
    coroutine.yield()
  end
end)
coroutine.resume(co)
coroutine.resume(co)
coroutine.resume(co)

Coroutines provide fine-grained flow control without OS threads. Each yield suspends execution and resumes exactly where it left off.

LuaJIT FFI Optimization

ffi_opt.lua
local ffi = require("ffi")
ffi.cdef[[
  typedef struct { double x, y; } Point;
]]
local Point = ffi.typeof("Point")
local p = Point(1.0, 2.0)
print(p.x + p.y)

LuaJIT's FFI enables calling native C code with zero overhead. Use it for critical loops to achieve near-C performance.

High-Performance Module

perf_module.lua
local M = {}
M.cache = setmetatable({}, {__mode = "v"})
function M.compute(key, fn)
  if M.cache[key] then return M.cache[key] end
  local res = fn()
  M.cache[key] = res
  return res
end
return M

This module implements a weak cache using mode 'v'. It prevents memory leaks while speeding up repeated calculations.

Benchmarking and Profiling

benchmark.lua
local start = os.clock()
for i = 1, 1000000 do
  -- code à mesurer
end
print("Temps:", os.clock() - start)

Use os.clock for precise measurements. Combine with LuaJIT -joff to compare JIT versus interpreted performance.

Best Practices

  • Prefer local tables over globals
  • Avoid creating closures in hot loops
  • Use collectgarbage("count") to monitor memory
  • Precompile scripts with luac -O3
  • Always test with and without JIT

Common Mistakes to Avoid

  • Forgetting rawget/rawset in metamethods creates infinite recursion
  • Using coroutines with non-yield-safe resources
  • Ignoring differences between Lua and LuaJIT in production
  • Failing to clear weak caches regularly

Further Reading

Deepen your knowledge with our advanced Lua training.