簡體   English   中英

Memory 泄漏 - 瀏覽器中的垃圾收集不收集組件

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

Angular 組件 Memory 泄漏 - 在 Chrome 和 Microsoft Edge 上(可能是所有瀏覽器,尚未測試所有瀏覽器)

  • 我已經在 Angular 11、12 和 13 的最新版本上嘗試了下面的應用程序,並且我已經能夠讓它們全部泄漏 memory
  • 瀏覽器不會在 Angular 組件被銷毀時進行垃圾回收
  • 組件淺尺寸(來自 memory 檢查器)看起來很小,但保留尺寸(來自 memory 檢查器)很大
  • DOM 節點保留在 memory 中,導致嚴重的 memory 泄漏
  • 我已經能夠讓這個程序在 Chrome 和 Edge 中導致 memory 泄漏(還沒有嘗試過任何其他程序)
  • 它發生在 angular 的開發和生產模式中
  • 它可能與 css 屬性有關,顯示:flex
  • 我無法在 stackblitz 上重現泄漏。 我只能讓它在本地運行應用程序的機器上運行

有時不會泄露memory,有時會。 這就是使它成為我一段時間以來遇到的最令人頭疼的問題之一的原因。

如果您第一次運行下面的程序並且它沒有泄漏 memory,請不要因為“我無法復制,所以它一定是假的”而立即將其注銷。請先嘗試幾次。 我發誓它最終會在啟動時進入 state(因為這個錯誤已經困擾我一段時間),導致它泄漏 memory。

我已將其縮小到這個簡單的應用程序,因為這個 memory 泄漏一直困擾着我一直在開發的一個更大的生產應用程序。

下面是可用於測試的簡化應用程序。

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"
  }
}

應用程序模塊.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>

應用程序組件.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 分離元素查看器和 Memory 檢查器 - 版本 97.0.1072.55

Chrome Memory 檢查器 - 版本 97.0.4692.99

DOM 節點爬升的可視化 - 您可以手動垃圾收集垃圾郵件,但它不會收集組件

任何關於這是 angular 錯誤、瀏覽器錯誤的任何輸入,或者如果您能指出可以幫助我解決這個問題的合適人選,我們將不勝感激。


這個問題是一個瀏覽器錯誤。 它已被 Chromium 開發團隊修復。 請參閱“原始 Angular 問題帖子”中的最后一個帖子

原Angular問題貼: https://github.com/angular/angular/issues/45080

Chromium 錯誤指定修復: https://bugs.chromium.org/p/chromium/issues/detail?id=1308845

此錯誤已在 Chrome 版本 M102 中修復: 請參閱 Chromium 錯誤報告。

發生泄漏是因為 LayoutInline 被添加到TextAutoresizer::fingerprints_但從未被刪除。 LayoutBlocks 被移除是因為它從WillBeDestroyed()調用TextAutoresizer::Destroy() ) 。 Oilpanize CL 只是使泄漏更大,因為現在我們保留了TextAutoresizer::fingerprints_指向的 LayoutObjects。

泄漏檢測器無法捕獲此泄漏,因為 TextAutoresizer 歸文檔所有,因此泄漏將 go 在導航中消失。

以下修訂是指此錯誤: https://chromium.googlesource.com/chromium/src/+/3b3305a8d8566a9ba5ef6ccf9d363e6497f06356

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

LayoutInline 應該從TextAutosizer::FingerprintMapper中移除

LayoutInline 未從TextAutosizer::FingerprintMapper::fingerprints_中刪除,導致 memory 泄漏。

此 CL 從WillBeDestroyed()中的 TextAutosizer 中刪除了 LayoutInline。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM