简体   繁体   English

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

[英]Memory Leak - Garbage Collection in Browser Not Collecting Components

Angular Component Memory Leak - on Chrome and Microsoft Edge (could be all browsers, haven't tested all of them yet) Angular 组件 Memory 泄漏 - 在 Chrome 和 Microsoft Edge 上(可能是所有浏览器,尚未测试所有浏览器)

  • I've tried the app below on the latest versions of Angular 11, 12, and 13, and I've been able to get them all to leak memory我已经在 Angular 11、12 和 13 的最新版本上尝试了下面的应用程序,并且我已经能够让它们全部泄漏 memory
  • browser isn't garbage collecting Angular components when they get destroyed浏览器不会在 Angular 组件被销毁时进行垃圾回收
  • the components shallow size (from the memory inspector) seems small, but the retained size (from the memory inspector) is large组件浅尺寸(来自 memory 检查器)看起来很小,但保留尺寸(来自 memory 检查器)很大
  • DOM Nodes are kept in memory, causing a significant memory leak DOM 节点保留在 memory 中,导致严重的 memory 泄漏
  • I've been able to get this program to cause memory leaks in Chrome and Edge (haven't tried any others yet)我已经能够让这个程序在 Chrome 和 Edge 中导致 memory 泄漏(还没有尝试过任何其他程序)
  • it happens in both dev and production mode of angular它发生在 angular 的开发和生产模式中
  • it could have todo with the css property, display: flex它可能与 css 属性有关,显示:flex
  • I can't reproduce the leak on stackblitz.我无法在 stackblitz 上重现泄漏。 I can only get it to work on machines running the app locally我只能让它在本地运行应用程序的机器上运行

Sometimes it won't leak memory, sometimes it will.有时不会泄露memory,有时会。 That's what makes this one of the biggest head scratchers I've faced in a while.这就是使它成为我一段时间以来遇到的最令人头疼的问题之一的原因。

Please don't immediately write this off as "I can't replicate, so it must be fake", if when you first run the program below and it doesn't leak memory. Try it a couple times first, please.如果您第一次运行下面的程序并且它没有泄漏 memory,请不要因为“我无法复制,所以它一定是假的”而立即将其注销。请先尝试几次。 I swear it will eventually get into a state when started (because this bug has been plaguing me for a while), that causes it to leak memory.我发誓它最终会在启动时进入 state(因为这个错误已经困扰我一段时间),导致它泄漏 memory。

I've narrow it down to this simple app, since this memory leak has been messing with a much larger production app that I've been working on.我已将其缩小到这个简单的应用程序,因为这个 memory 泄漏一直困扰着我一直在开发的一个更大的生产应用程序。

Below is the simplified app that can be used to test with.下面是可用于测试的简化应用程序。

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

package.json 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应用程序模块.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 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应用程序组件.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 Microsoft Edge 分离元素查看器和 Memory 检查器 - 版本 97.0.1072.55

Chrome Memory Inspector - Version 97.0.4692.99 Chrome Memory 检查器 - 版本 97.0.4692.99

Visual of DOM Nodes Climbing - You can spam manual garbage collection and it won't collect the components DOM 节点爬升的可视化 - 您可以手动垃圾收集垃圾邮件,但它不会收集组件

Any input as to if this is an angular bug, a browser bug, or if you could point me to the right person that could help me figure this out would be greatly appreciated.任何关于这是 angular 错误、浏览器错误的任何输入,或者如果您能指出可以帮助我解决这个问题的合适人选,我们将不胜感激。


This issue was a browser bug.这个问题是一个浏览器错误。 It has been fixed by the chromium dev team.它已被 Chromium 开发团队修复。 See the last post within "Original Angular issue post"请参阅“原始 Angular 问题帖子”中的最后一个帖子

Original Angular issue post: https://github.com/angular/angular/issues/45080原Angular问题贴: https://github.com/angular/angular/issues/45080

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

This bug has been fixed in Chrome Version M102: See Chromium Bug Report.此错误已在 Chrome 版本 M102 中修复: 请参阅 Chromium 错误报告。

The leak happens because LayoutInline gets added to TextAutoresizer::fingerprints_ but is never removed.发生泄漏是因为 LayoutInline 被添加到TextAutoresizer::fingerprints_但从未被删除。 LayoutBlocks gets removed because it calls TextAutoresizer::Destroy() from WillBeDestroyed() . LayoutBlocks 被移除是因为它从WillBeDestroyed()调用TextAutoresizer::Destroy() ) 。 The Oilpanize CL just made the leak bigger because now we retain LayoutObjects pointed by TextAutoresizer::fingerprints_ . Oilpanize CL 只是使泄漏更大,因为现在我们保留了TextAutoresizer::fingerprints_指向的 LayoutObjects。

The leak detector could not catch this leak because TextAutoresizer is owned by the document so the leak will go away on navigation.泄漏检测器无法捕获此泄漏,因为 TextAutoresizer 归文档所有,因此泄漏将 go 在导航中消失。

The following revision refers to this bug: https://chromium.googlesource.com/chromium/src/+/3b3305a8d8566a9ba5ef6ccf9d363e6497f06356以下修订是指此错误: https://chromium.googlesource.com/chromium/src/+/3b3305a8d8566a9ba5ef6ccf9d363e6497f06356

commit 3b3305a8d8566a9ba5ef6ccf9d363e6497f06356 Author: Keishi Hattori keishi@chromium.org Date: Mon Apr 04 23:34:17 2022 commit 3b3305a8d8566a9ba5ef6ccf9d363e6497f06356 作者:Keishi Hattori keishi@chromium.org 日期:2022 年 4 月 4 日星期一 23:34:17

LayoutInline should be removed from TextAutosizer::FingerprintMapper LayoutInline 应该从TextAutosizer::FingerprintMapper中移除

LayoutInline was not removed from TextAutosizer::FingerprintMapper::fingerprints_ causing a memory leak. LayoutInline 未从TextAutosizer::FingerprintMapper::fingerprints_中删除,导致 memory 泄漏。

This CL removed LayoutInline from TextAutosizer in WillBeDestroyed() .此 CL 从WillBeDestroyed()中的 TextAutosizer 中删除了 LayoutInline。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM