内存泄漏 - 浏览器中的垃圾收集不收集组件

Memory Leak - Garbage Collection in Browser Not Collecting Components

Angular 组件内存泄漏 - Chrome 和 Microsoft Edge(可能是所有浏览器,尚未测试所有浏览器)

有时不会泄漏内存,有时会。这就是使它成为我一段时间以来遇到的最令人头疼的问题之一的原因。

如果你第一次运行下面的程序,请不要因为“我无法复制,所以它一定是假的”而立即注销而且它不会泄漏内存。请先尝试几次。我发誓它最终会在启动时进入一个状态(因为这个错误已经困扰我一段时间了),导致它泄漏内存。

我已经将它缩小到这个简单的应用程序,因为这个内存泄漏一直困扰着我一直在处理的一个更大的生产应用程序。

以下是可用于测试的简化应用程序。

https://github.com/kevinpbaker/angular-memory-killer

package.json

{
  "name": "memory-killer",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve --port 4201",
    "build": "ng build --prod --aot --buildOptimizer --commonChunk --vendorChunk --optimization --progress",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~11.2.14",
    "@angular/cdk": "^11.2.13",
    "@angular/common": "~11.2.14",
    "@angular/compiler": "~11.2.14",
    "@angular/core": "~11.2.14",
    "@angular/forms": "~11.2.14",
    "@angular/material": "^11.2.13",
    "@angular/platform-browser": "~11.2.14",
    "@angular/platform-browser-dynamic": "~11.2.14",
    "@angular/router": "~11.2.14",
    "rxjs": "~6.5.4",
    "rxjs-compat": "^6.5.5",
    "zone.js": "~0.11.4"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.1102.18",
    "@angular/cli": "~11.2.18",
    "@angular/compiler-cli": "~11.2.14",
    "@angular/language-service": "~11.2.14",
    "@types/jasmine": "~3.6.0",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "^12.11.1",
    "codelyzer": "^6.0.0",
    "jasmine-core": "~4.0.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~6.3.13",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~3.0.2",
    "karma-jasmine": "~4.0.0",
    "karma-jasmine-html-reporter": "^1.7.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "tslint": "~6.1.0",
    "typescript": "4.0.8"
  }
}

app.module.ts

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {AppComponent, MemoryKiller2Component, MemoryKillerComponent} from './app.component';

@NgModule({
  declarations: [
    AppComponent,
    MemoryKillerComponent,
    MemoryKiller2Component
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Memory Killer</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root></app-root>
</body>
</html>

app.component.ts

import {Component} from '@angular/core';
import {timer} from 'rxjs';
import {map} from 'rxjs/operators';

@Component({
  selector: 'app-root',
  template: '<app-memory-killer *ngIf="killCycle$|async"></app-memory-killer>',
})
export class AppComponent {
  // change 1000 to 1 if you want to speed up the memory killer
  killCycle$ = timer(0, 1000).pipe(map(k => k % 2 !== 0));
}

@Component({
  selector: 'app-memory-killer',
  template: `
    <div class="memory-killer">
      <app-memory-killer2></app-memory-killer2>
      <app-memory-killer2></app-memory-killer2>
      <app-memory-killer2></app-memory-killer2>
    </div>
  `,
  styles: [`.memory-killer { display: flex; }`]
})
export class MemoryKillerComponent { }

@Component({
  selector: 'app-memory-killer2',
  template: `
    <div class="memory-killer2">
      <div>Killing your memory</div>
      <div>Killing your memory</div>
      <div>Killing your memory</div>
    </div>
  `,
  styles: [`.memory-killer2 { display: flex; }`],
})
export class MemoryKiller2Component { }

Microsoft Edge Detached Elements Viewer and Memory Inspector - Version 97.0.1072.55

Chrome Memory Inspector - Version 97.0.4692.99

Visual of DOM Nodes Climbing - You can spam manual garbage collection and it won't collect the components

任何关于这是 angular 错误、浏览器错误的任何输入,或者如果你能指出合适的人可以帮助我解决这个问题,我们将不胜感激。


此问题是浏览器错误。它已由 chromium 开发团队修复。请参阅“原始 Angular 期 post”中的最后 post“

原始 Angular 问题 post:https://github.com/angular/angular/issues/45080

指定修复的 Chromium 错误:https://bugs.chromium.org/p/chromium/issues/detail?id=1308845

此错误已在 Chrome 版本 M102 中修复:See Chromium Bug Report.

The leak happens because LayoutInline gets added to TextAutoresizer::fingerprints_ but is never removed. LayoutBlocks gets removed because it calls TextAutoresizer::Destroy() from WillBeDestroyed(). The Oilpanize CL just made the leak bigger because now we retain LayoutObjects pointed by TextAutoresizer::fingerprints_.

The leak detector could not catch this leak because TextAutoresizer is owned by the document so the leak will go away on navigation.

The following revision refers to this bug: https://chromium.googlesource.com/chromium/src/+/3b3305a8d8566a9ba5ef6ccf9d363e6497f06356

commit 3b3305a8d8566a9ba5ef6ccf9d363e6497f06356 Author: Keishi Hattori keishi@chromium.org Date: Mon Apr 04 23:34:17 2022

LayoutInline should be removed from TextAutosizer::FingerprintMapper

LayoutInline was not removed from TextAutosizer::FingerprintMapper::fingerprints_ causing a memory leak.

This CL removed LayoutInline from TextAutosizer in WillBeDestroyed().