angular: __ngContext__ magnifies native Chrome memory leaks
🐞 bug report
Affected Package
@angular/core@11.2.3
Is this a regression?
No.
Description
Small memory leaks become large leaks when Angular monkey patches __ngContext__
onto dom.
For example, take this issue. After typing into textareas, the issue leads to detached HTMLTextAreaElements because of the native undo stack.
It is a small leak that has nothing to do with Angular. It is only a few KBs:
But, with Angular components in the mix, those KBs become MBs:
It looks like __ngContext__
, retains almost everything, even though the textarea is a vanilla element:
And if we remove this call from @angular/core
:
🔬 Minimal Reproduction
https://github.com/blidblid/ng-context-memory-leak
- ng s --prod
- Type in the textarea to create the Chrome leak
- Press Destroy and create
- Repeat with @angular/material components included
The issue is also present on material.angular.io. Typing in a textarea and navigating the sidenav will cause large leaks.
🌍 Your Environment
Angular Version:
Angular CLI: 11.2.2
Node: 14.15.0
OS: win32 x64
Angular: 11.2.3
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router
Ivy Workspace: Yes
Package Version
---------------------------------------------------------
@angular-devkit/architect 0.1100.7
@angular-devkit/build-angular 0.1100.7
@angular-devkit/core 11.0.7
@angular-devkit/schematics 11.2.2
@angular/cdk 11.2.2
@angular/cli 11.2.2
@angular/material 11.2.2
@schematics/angular 11.2.2
@schematics/update 0.1102.2
rxjs 6.6.6
typescript 4.0.7
Anything else relevant?
Chrome 88.0.4324.190
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 31
- Comments: 29 (15 by maintainers)
Commits related to this issue
- fix(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sav... — committed to crisbeto/angular by crisbeto 3 years ago
- fix(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sav... — committed to crisbeto/angular by crisbeto 3 years ago
- fix(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sav... — committed to crisbeto/angular by crisbeto 3 years ago
- fix(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sav... — committed to crisbeto/angular by crisbeto 3 years ago
- fix(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sav... — committed to crisbeto/angular by crisbeto 3 years ago
- fix(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sav... — committed to crisbeto/angular by crisbeto 3 years ago
- fix(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sav... — committed to crisbeto/angular by crisbeto 3 years ago
- fix(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sav... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sa... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sa... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sa... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sa... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sa... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sa... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sa... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__` or by sa... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ (#41358) Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView` directly in the `__ngContext__`... — committed to angular/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ These changes combine #41358 and #41894. Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView... — committed to crisbeto/angular by crisbeto 3 years ago
- perf(core): avoid storing LView in __ngContext__ These changes combine #41358 and #41894. Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView... — committed to crisbeto/angular by crisbeto 2 years ago
- perf(core): avoid storing LView in __ngContext__ These changes combine #41358 and #41894. Currently we save a reference to an `LView` on most DOM nodes created by Angular either by saving the `LView... — committed to crisbeto/angular by crisbeto 2 years ago
We discussed this some more and think we might be able to use
requestIdleCallback
to directly clear__ngContext__
(and mitigate DOM memory leaks outside our control) without incurring runtime performance penalty. We’d definitely have to try this out with a number of different apps, though, to see the real-world impact.@mhevery Does this also apply to patching native elements specifically?
From our perspective, this issue would put 100.000 healthcare workers on ViewEngine indefinitely. That’s a huge blow, because Ivy is amazing and because we’ll be stranded with an old Angular version. The background here is that the hospital environments usually have 100-200 MB of RAM. And if the framework magnifies leaks by a factor thousand, those environments will go down.
I get that the reproduction above uses a Chrome issue, but the role of
__ngContext__
as a massive retainer applies to any leak. Angular has 13 open memory leaks. We have some, rxjs has some, Chrome has some. Any large app will leak a bit, and that’s fine as long as those leaks are small and self-contained.__ngContext__
removes that containment.I’m happy to rephrase the issue to “ngContext magnifies memory leaks” if you think that is a better angle here.
You are a life saver! With a similar fix our app is now smooth and performant on even the slower iOs Air2s ( ours is a hybrid ionic Ng app ). Basically we have 100s of cards that can be paginated back and forth and the dom nodes and memory were climbing up. We added this “hack” and the UI is now much better than ever. Our diffs for the patch were
and our patch , in npm post-install is to call this after the
ngcc
has executed:-The downside is we have to keep track when we update Angular
Update on my previous comment: it seems like I overlooked something in my previous fix which can cause some different memory leaks. I’ve submitted https://github.com/angular/angular/pull/41894 to resolve them and I expect the fix to be in the RC release next week.
We’ve merged in a fix for this which will be out in the next RC version. It would be valuable to know if the changes resolved the memory leaks for you.
Besides that I agree with @kallebjork I’m also curious about what APIs need this in production and why.