Hello, I have technical questions regarding SLua timer behavior and recursive/self-rescheduling callbacks.
I’m using the following pattern, where a function schedules itself again using LLTimers:once(). The snippet below is a highly simplified version of the real use case, included only to demonstrate the issue (I’m aware of LLTimers:every()).
```lua
local main
main = function()
ll.SetText(tostring(ll.GetTime()) .. "\n" .. tostring(ll.GetFreeMemory()), vector(1, 1, 1), 1)
LLTimers:once(1, main)
end
main()
```
Issue observed
With this code,
ll.GetFreeMemory()
steadily decreases over time, as if memory is being accumulated or not released correctly.
Why I’m asking (comparison with LSL habits)
In LSL, it’s very common to avoid recursive loops by using
llSetTimerEvent(x)
—the timer event triggers again later without building up a recursive call chain. So from an LSL perspective, the pattern “schedule again in 1 second” is typically considered safe and non-recursive in practice.
With SLua +
LLTimers:once()
, I expected a similar behavior (a clean callback invocation each tick), but the memory decrease makes me wonder if this pattern is internally treated as a form of recursion that keeps references/callbacks alive longer than expected.
Questions
  1. Is this memory decrease expected behavior when using
    LLTimers:once()
    in a self-rescheduling callback?
  2. Internally, are timer callbacks handled in a way that could retain closures/references across calls (causing memory to accumulate)?
  3. Would it be possible (now or in the future) for timer callbacks to be executed in a way that breaks this “recursive” chaining—e.g., treated like an isolated execution context (separate thread-like handling or a coroutine-style dispatch)—so that each timer tick runs cleanly without retaining the previous call context?
Real use case
The simplified example above is only to demonstrate the problem. In real scripts, I have a controller function that checks multiple conditions and schedules follow-up actions with different delays (sometimes calling other functions that schedule additional timers, and sometimes rescheduling the original function). This makes
LLTimers:every()
unsuitable in many cases, because the next delay depends on the outcome of the current step.
Thanks in advance for any clarification on whether this is expected. For now, as a workaround, I use linked messages to schedule new timers that execute the desired functions after a given delay.