SIGN IN SIGN UP
bevyengine / bevy UNCLAIMED

A refreshingly simple data-driven game engine built in Rust

0 0 59 Rust

Tracked one-shot systems (#24165)

# Objective

#24087 introduces scene templating for `SystemId`s, however it can
result in a memory leak if a scene is re-constructed multiple times:

https://github.com/bevyengine/bevy/pull/24087#issuecomment-4365730489
> This was proposed basically 1:1 in #24026 (this was later changed
though). The issue is that it's unclear who owns these systems, that is
who is responsible for unregistering them once they are no longer
needed. Given that recreating the template will spawn the system again
this basically becomes a memory leak.

https://github.com/bevyengine/bevy/pull/24087#issuecomment-4366075669
> > Hm, are you sure this is the case even tho in `build_template` it
only registers the system the first time its called, switching over to
storing the SystemId after the first call?
>
> If you recreate the template (e.g. you call `my_scene()` again) then
you will create a new instance of the system. And since the system is
not scoped to the scene once the scene is despawned the system entity
will be leaked.

Essentially, we need a way to connect the lifetime of the registered
system to the lifetime of the scene.

## Solution

This is a purely additive / opt-in / backwards-compatible version of
#24114

Introducing: `SystemHandle`s

```rust
pub enum SystemHandle<I: SystemInput = (), O = ()> {
    /// A strong handle keeps the system entity alive as long as the handle
    /// (and any clones of it) exist.
    Strong(Arc<StrongSystemHandle>),
    /// A weak handle does not keep the system entity alive.
    Weak(SystemId<I, O>),
}

pub struct StrongSystemHandle {
    entity: Entity,
    drop_queue: Arc<ConcurrentQueue<<Entity>>,
}
```

Similar to `bevy_asset::Handle`s,`SystemHandle`'s custom `Drop`
implementation enqueues the registered system entity into a concurrent
queue. The system `despawn_unused_registered_systems` pulls from the
other end of this queue and despawns the registered system entities.

`World::register_tracked_system` and
`World::register_tracked_boxed_system` are the only functions that
return `SystemHandle`s.

## Testing

- Added a test to ensure that `despawn_unused_registered_systems` does
its job
- Added a test to ensure that the default app will automatically call
`despawn_unused_registered_systems`

## Future work

- #24087 will use this PR as a base

---------

Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
C
Christian Hughes committed
b5f5a4212991a48952fb69b9318f971ac168434a
Parent: 398f824
Committed by GitHub <noreply@github.com> on 5/22/2026, 11:09:58 AM