fix(core): scope reactive consumer pool per ApplicationRef #64978
+75
−14
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This issue has been captured in real-world scenarios multiple times,
particularly in SSR environments and micro-frontend applications where
memory leaks were observed after repeated application bootstrapping
and destruction cycles.
Previously, the
freeConsumersarray was a module-level singletonthat accumulated consumers across multiple application lifecycles.
This caused memory leaks in the following scenarios:
Without proper scoping, each destroyed application left its pooled
consumers in memory, leading to unbounded growth over time.
This change replaces the global array with a
WeakMapkeyed byApplicationRef.ApplicationRefis used instead ofEnvironmentInjectorbecause there is only one
ApplicationRefper application, whereas thereare many
EnvironmentInjectorinstances (per route, defer block, etc.).This ensures:
memory reuse
is destroyed (when the
ApplicationRefis GC'd)consumer recycling
ApplicationRefThe implementation uses optional injection for
ApplicationRefto maintainbackward compatibility with existing tests (both OSS and G3) that create
components with custom injectors. In edge cases where
ApplicationRefisnot available, consumers are created/discarded without pooling.
While it is barely possible to create a unit test that reliably
reproduces this multi-application scenario (due to module-level state
and the need to simulate multiple app lifecycles in the same process),
the
WeakMapapproach is fundamentally safer than the previous globalsingleton and the fix is necessary without considerations.
Fixes memory leaks in production SSR deployments and micro-frontend
architectures.