Skip to content

Commit b6f7205

Browse files
crisbetommalerba
authored andcommitted
perf(tree): leaking reference through mostRecentTreeNode (#12334)
Along the same lines as #12269. Clears out the `mostRecentTreeNode` once the last tree node is destroyed, in order to avoid a memory leak.
1 parent 1599892 commit b6f7205

File tree

2 files changed

+22
-2
lines changed

2 files changed

+22
-2
lines changed

src/cdk/tree/tree.spec.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {TreeControl} from './control/tree-control';
1717
import {FlatTreeControl} from './control/flat-tree-control';
1818
import {NestedTreeControl} from './control/nested-tree-control';
1919
import {CdkTreeModule} from './index';
20-
import {CdkTree} from './tree';
20+
import {CdkTree, CdkTreeNode} from './tree';
2121
import {getTreeControlFunctionsMissingError} from './tree-errors';
2222

2323

@@ -35,6 +35,20 @@ describe('CdkTree', () => {
3535
}).compileComponents();
3636
}
3737

38+
it('should clear out the `mostRecentTreeNode` on destroy', () => {
39+
configureCdkTreeTestingModule([SimpleCdkTreeApp]);
40+
const fixture = TestBed.createComponent(SimpleCdkTreeApp);
41+
fixture.detectChanges();
42+
43+
// Cast the assertions to a boolean to avoid Jasmine going into an
44+
// infinite loop when stringifying the object, if the test starts failing.
45+
expect(!!CdkTreeNode.mostRecentTreeNode).toBe(true);
46+
47+
fixture.destroy();
48+
49+
expect(!!CdkTreeNode.mostRecentTreeNode).toBe(false);
50+
});
51+
3852
describe('flat tree', () => {
3953
describe('should initialize', () => {
4054
let fixture: ComponentFixture<SimpleCdkTreeApp>;

src/cdk/tree/tree.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ export class CdkTree<T>
290290
'class': 'cdk-tree-node',
291291
},
292292
})
293-
export class CdkTreeNode<T> implements FocusableOption, OnDestroy {
293+
export class CdkTreeNode<T> implements FocusableOption, OnDestroy {
294294
/**
295295
* The most recently created `CdkTreeNode`. We save it in static variable so we can retrieve it
296296
* in `CdkTree` and set the data to it.
@@ -328,6 +328,12 @@ export class CdkTreeNode<T> implements FocusableOption, OnDestroy {
328328
}
329329

330330
ngOnDestroy() {
331+
// If this is the last tree node being destroyed,
332+
// clear out the reference to avoid leaking memory.
333+
if (CdkTreeNode.mostRecentTreeNode === this) {
334+
CdkTreeNode.mostRecentTreeNode = null;
335+
}
336+
331337
this._destroyed.next();
332338
this._destroyed.complete();
333339
}

0 commit comments

Comments
 (0)