fix(core): avoid leaking memory if component throws during creation (#57546)

When we create the LView for a component, we track it in the `TRACKED_LVIEWS` map. It gets untracked when it is destroy, but if it throws during creation, the user won't have access to a `ComponentRef` in order to clean it up.

These changes automatically untrack the related LViews if the component couldn't be created.

PR Close #57546
This commit is contained in:
Kristiyan Kostadinov 2024-08-27 12:27:55 +02:00 committed by Alex Rickabaugh
parent 099955bdf3
commit a3cdbfe87f
12 changed files with 44 additions and 1 deletions

View file

@ -88,6 +88,7 @@ import {debugStringifyTypeForError, stringifyForError} from './util/stringify_ut
import {getComponentLViewByIndex, getNativeByTNode, getTNode} from './util/view_utils';
import {ViewRef} from './view_ref';
import {ChainedInjector} from './chained_injector';
import {unregisterLView} from './interfaces/lview_tracking';
export class ComponentFactoryResolver extends AbstractComponentFactoryResolver {
/**
@ -333,6 +334,7 @@ export class ComponentFactory<T> extends AbstractComponentFactory<T> {
let component: T;
let tElementNode: TElementNode;
let componentView: LView | null = null;
try {
const rootComponentDef = this.componentDef;
@ -354,7 +356,7 @@ export class ComponentFactory<T> extends AbstractComponentFactory<T> {
}
const hostTNode = createRootComponentTNode(rootLView, hostRNode);
const componentView = createRootComponentView(
componentView = createRootComponentView(
hostTNode,
hostRNode,
rootComponentDef,
@ -388,6 +390,14 @@ export class ComponentFactory<T> extends AbstractComponentFactory<T> {
[LifecycleHooksFeature],
);
renderView(rootTView, rootLView, null);
} catch (e) {
// Stop tracking the views if creation failed since
// the consumer won't have a way to dereference them.
if (componentView !== null) {
unregisterLView(componentView);
}
unregisterLView(rootLView);
throw e;
} finally {
leaveView();
}

View file

@ -1478,6 +1478,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "unwrapRNode"
},

View file

@ -1553,6 +1553,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "unwrapRNode"
},

View file

@ -1253,6 +1253,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "unwrapRNode"
},

View file

@ -2498,6 +2498,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "unwrapRNode"
},

View file

@ -1889,6 +1889,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "untracked"
},

View file

@ -1871,6 +1871,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "untracked"
},

View file

@ -995,6 +995,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "unwrapRNode"
},

View file

@ -1385,6 +1385,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "unwrapRNode"
},

View file

@ -2159,6 +2159,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "unwrapElementRef"
},

View file

@ -1103,6 +1103,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "unwrapRNode"
},

View file

@ -1505,6 +1505,9 @@
{
"name": "uniqueIdCounter"
},
{
"name": "unregisterLView"
},
{
"name": "unwrapRNode"
},