
# Objective Reduce memory usage by storing fewer copies of `FilteredAccessSet<ComponentId>`. Currently, the `System` trait exposes the `component_access_set` for the system, which is used by the multi-threaded executor to determine which systems can run concurrently. But because it is available on the trait, it needs to be stored for *every* system, even ones that are not run by the executor! In particular, it is never needed for observers, or for the inner systems in a `PipeSystem` or `CombinatorSystem`. ## Solution Instead of exposing the access from a method on `System`, return it from `System::initialize`. Since it is still needed during scheduling, store the access alongside the boxed system in the schedule. That's not quite enough for systems built using `SystemParamBuilder`s, though. Those calculate the access in `SystemParamBuilder::build`, which happens earlier than `System::initialize`. To handle those, we separate `SystemParam::init_state` into `init_state`, which creates the state value, and `init_access`, which calculates the access. This lets `System::initialize` call `init_access` on a state that was provided by the builder. An additional benefit of that separation is that it removes the need to duplicate access checks between `SystemParamBuilder::build` and `SystemParam::init_state`. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2.1 KiB
title | pull_requests | ||
---|---|---|---|
Stop storing access in systems |
|
Bevy used to store component access in all systems, even though it was only used for top-level systems in schedules. To reduce memory usage, the component access is now stored in the schedule instead.
The trait methods System::component_access
and System::component_access_set
have been removed.
Instead, the access is returned from System::initialize
.
If you were implementing System
manually, the initialize
method should return the access instead of storing it.
If you were calling component_access
or component_access_set
on a system that you initialized yourself,
you will need to store the access yourself.
let system = IntoSystem::into_system(your_system);
// 0.16
system.initialize(&mut world);
let access = system.component_access();
// 0.17
let component_access_set = system.initialize(&mut world);
let access = component_access_set.combined_access();
SystemMeta
no longer stores FilteredAccessSet<ComponentId>
.
It is instead passed as a separate parameter when initializing a SystemParam
.
To better share logic between SystemParam
and SystemParamBuilder
,
SystemParam::init_state
has been split into init_state
, which creates the state value, and init_access
, which calculates the access.
SystemParamBuilder::build
now only creates the state, and SystemParam::init_access
will be called to calculate the access for built parameters.
If you were implementing SystemParam
manually, you will need to separate the logic into two methods
and change any uses of system_meta.component_access_set(_mut)
to the new component_access_set
parameter.
Note that init_state
no longer has access to SystemMeta
or component_access_set
, and init_access
only has &state
, so the state can no longer depend on the system.
If you were calling init_state
manually, you will need to call init_access
afterwards.
// 0.16
let param_state = P::init_state(world, &mut meta);
// 0.17
let param_state = P::init_state(world);
let mut component_access_set = FilteredAccessSet::new();
P::init_access(¶m_state, &mut meta, &mut component_access_set, world);