PiTyUs.Hire me

Engineering

Finding and fixing memory leaks in FiveM resources

Track down memory growth in FiveM Lua resources: the usual causes (per-player tables never cleaned, handlers registered repeatedly, entities never deleted, growing caches), measuring with resmon and collectgarbage('count'), cleanup on playerDropped and onResourceStop, and caching with limits.

Updated 9 min readBy PiTyUs · FiveM developer

Overview

A resource that uses 2 MB after a restart and 200 MB six hours later is leaking. Lua has a garbage collector, so leaks in FiveM scripts are almost never lost memory — they are data your code keeps a reference to and never lets go: a table keyed by player that nobody cleans, a cache without a limit, an event handler added again on every call.

Measuring

server.lua — log memory every 5 minuteslua
CreateThread(function()
    while true do
        Wait(300000)
        print(('[%s] Lua memory: %.1f MB'):format(GetCurrentResourceName(), collectgarbage('count') / 1024))
    end
end)

Short spikes are normal — the collector runs in steps. A line that keeps rising across hours is a leak. Resmon shows per-resource numbers on the client — see resmon explained.

The usual causes

CauseFix
data[source] = ... never removedClear it in playerDropped
AddEventHandler inside another handlerRegister once at file level
CreateThread per action that never endsLet threads exit, or reuse one loop
Caches that only growSize limit or time-based expiry
Entities, blips, zones never removedDelete them when done and on resource stop
Big strings built repeatedlyBuild once; use table.concat

Cleanup patterns

server.lualua
local sessions = {}

AddEventHandler('playerDropped', function()
    sessions[source] = nil
end)

local cache, order, MAX = {}, {}, 500
local function remember(key, value)
    if not cache[key] then
        order[#order + 1] = key
        if #order > MAX then cache[table.remove(order, 1)] = nil end
    end
    cache[key] = value
end

AddEventHandler('onResourceStop', function(res)
    if res ~= GetCurrentResourceName() then return end
    -- delete entities, blips and zones created by this resource
end)

Handlers registered inside loops are also a correctness bug: each one fires, so events run several times. Event basics: events explained.

Client-side leaks

  • Props and peds spawned for effects and never deleted.
  • NUI elements created on every message and never removed.
  • Streamed textures requested repeatedly without releasing them.
  • ox_lib points and zones created on every enter instead of once.

Frequently asked questions

How do I check a FiveM resource’s memory use?

Use resmon on the client or print collectgarbage('count') (in KB) from the resource over time.

Does Lua garbage collection prevent leaks?

It frees unreferenced data. Leaks happen when your code keeps references, such as tables that are never cleaned.

What is the most common leak in FiveM scripts?

Per-player data stored by source and never cleared when the player leaves.

Will a server restart fix leaks?

It resets memory, but the leak returns. Fix the reference that keeps growing.

Need this built, not just explained?

Ten years of FiveM work, from Lua to NUI

Custom resources, React NUI, ESX / QBCore / Qbox integration, OneSync performance audits and security reviews — plus the websites and SEO around your server brand.

Related guides