Додаток Angular Firebase виходить з ладу через 20 годин з розподілом +1 гігабайт пам'яті


13

Я виявив, що використання AngularFireAuthModuleвід " '@angular/fire/auth';спричиняє витік пам'яті", який вибиває браузер через 20 годин.

Версія:

Я використовую останню оновлену сьогодні версію, використовуючи ncu -u для всіх пакетів.

Кутовий вогонь: "@angular/fire": "^5.2.3",

Firebase версія: "firebase": "^7.5.0",

Як відтворити:

Я зробив мінімальний відтворюваний код у редакторі StackBliztz

Ось посилання для тестування помилки безпосередньо на тесті StackBlizt

Симптом:

Ви можете переконатися, що код нічого не робить. Він просто друкує привіт світ. Однак пам'ять JavaScript, яка використовується програмою Angular, збільшується на 11 кбіт / с (Chrome Task Manager CRTL + ESC). Через 10 годин залишаючи браузер відкритим, використовувана пам'ять досягає приблизно 800 мб (слід пам’яті приблизно вдвічі більше 1,6 Гбіт !)

Як результат, у веб-переглядача не вистачає пам'яті, а вкладка хрому виходить з ладу.

Після подальшого дослідження за допомогою профілювання хромування пам'яті на вкладці продуктивності я чітко помітив, що кількість слухачів збільшується на 2 щосекунди, і відповідно купі JS збільшується відповідно.

введіть тут опис зображення

Код, що спричиняє витік пам'яті:

Я виявив, що використання AngularFireAuthModule модуля спричиняє витік пам'яті, вводиться він у componentконструктор чи в a service.

import { Component } from '@angular/core';
import {AngularFireAuth} from '@angular/fire/auth';
import {AngularFirestore} from '@angular/fire/firestore';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'memoryleak';
  constructor(public auth: AngularFireAuth){

  }
}

Питання :

Це може бути помилка у впровадженні FirebaseAuth, і я вже відкриваю випуск Github, але шукаю вирішення цього питання. Я відчайдушно шукаю рішення. Я не проти, навіть якщо сеанси на вкладках не синхронізовані. Мені ця функція не потрібна. Я десь це читав

якщо вам не потрібна ця функціональність, зусилля з модуляції Firebase V6 дозволять вам перейти на localStorage, який має події зберігання для виявлення перехресних вкладок змін, і, можливо, надасть вам можливість визначити власний інтерфейс зберігання.

Якщо це єдине рішення, як це здійснити?

Мені просто потрібно будь-яке рішення, яке зупиняє це непотрібне збільшення кількості слухачів, оскільки воно уповільнює роботу комп'ютера та вибиває з моєї програми. Моєму додатку потрібно працювати більше 20 годин, тому він зараз непридатний через цю проблему. Я відчайдушно шукаю рішення.



Я не зміг відтворити вашу проблему на вашому прикладі
Сергій Мелл

@SergeyMell Ви використовували код, який я розмістив на StackBlitz?
ТСР

Так. Власне, я говорю про це.
Сергій Мелл

Спробуйте завантажити код і запустити його локально. Я також завантажив його на диск на випадок drive.google.com/file/d/1fvo8eJrbYpZWfSXM5h_bw5jh5tuoWAB2/…
TSR

Відповіді:


7

TLDR: Збільшення кількості слухачів очікується поведінка і буде скинуто після збору сміття. Помилка, яка спричиняє протікання пам'яті у Firebase Auth, уже виправлена ​​у Firebase v7.5.0, див. # 1121 , перевірте package-lock.json, чи не використовується правильна версія. Якщо ви не впевнені, перевстановіть firebaseпакет.

Попередні версії Firebase було опитування IndexedDB через Promise зчеплення, що призводить до витоку пам'яті, див Promise в JavaScript Витоку пам'яті

var repeat = function() {
  self.poll_ =
      goog.Timer.promise(fireauth.storage.IndexedDB.POLLING_DELAY_)
      .then(goog.bind(self.sync_, self))
      .then(function(keys) {
        // If keys modified, call listeners.
        if (keys.length > 0) {
          goog.array.forEach(
              self.storageListeners_,
              function(listener) {
                listener(keys);
              });
        }
      })
      .then(repeat)
      .thenCatch(function(error) {
        // Do not repeat if cancelled externally.
        if (error.message != fireauth.storage.IndexedDB.STOP_ERROR_) {
          repeat();
        }
      });
  return self.poll_;
};
repeat();

Виправлено в наступних версіях з використанням нерекурсивних викликів функцій:

var repeat = function() {
  self.pollTimerId_ = setTimeout(
      function() {
        self.poll_ = self.sync_()
            .then(function(keys) {
              // If keys modified, call listeners.
              if (keys.length > 0) {
                goog.array.forEach(
                    self.storageListeners_,
                    function(listener) {
                      listener(keys);
                    });
              }
            })
            .then(function() {
              repeat();
            })
            .thenCatch(function(error) {
              if (error.message != fireauth.storage.IndexedDB.STOP_ERROR_) {
                repeat();
              }
            });
      },
      fireauth.storage.IndexedDB.POLLING_DELAY_);
};
repeat();


Щодо лінійно зростаючого числа слухачів:

Очікується лінійно зростаюча кількість слухачів, оскільки саме це Firebase робить для опитування IndexedDB. Однак слухачів буде видалено, коли GC захоче.

Прочитайте випуск 576302: Невірно показана протікання пам'яті (слухачі xhr та завантаження)

V8 періодично виконує Незначну ГК, що викликає ті невеликі краплі розміру купи. Насправді їх можна побачити на полум'ї. Однак неповнолітні GC можуть не збирати все сміття, що, очевидно, відбувається у слухачів.

Кнопка панелі інструментів викликає основні GC, здатні збирати слухачів.

DevTools намагається не заважати запущеному додатку, тому він не змушує GC самостійно.


Щоб підтвердити, що окремі слухачі збирають сміття, я додав цей фрагмент для тиску на групу JS, тим самим змушуючи GC спрацьовувати:

var x = ''
setInterval(function () {
  for (var i = 0; i < 10000; i++) {
    x += 'x'
  }
}, 1000)

Слухачі збирають сміття

Як бачите, відключені слухачі періодично видаляються, коли спрацьовує GC.



Подібні запитання щодо stackoverflow та проблеми GitHub щодо кількості слухачів та витоків пам'яті:

  1. Слухачі результатів профілювання інструментів Chrome для розробників
  2. Слухачі JavaScript постійно збільшуються
  3. Просте додаток, що спричиняє витік пам'яті?
  4. $ http 'GET' витік пам'яті (НЕ!) - кількість слухачів (AngularJS v.1.4.7 / 8)

Я підтверджую, використовуючи 7.5.0 і тестуючи кілька разів у різних середовищах. Навіть this.auth.auth.setPersistence ('none') не перешкоджає витоку пам'яті. Перевірте його, використовуючи код тут stackblitz.com/edit/angular-zuabzz
TSR

які ваші кроки тестування? Чи потрібно залишати його на ніч, щоб побачити збій браузера? У моєму випадку номер слухача завжди скидається після гри GC, а пам'ять завжди повертається до 160 Мб.
Джошуа Чан

@TSR виклик this.auth.auth.setPersistence('none')в ngOnInitзамість конструктора , щоб відключити наполегливість.
Джошуа Чан

@JoshuaChan має значення, коли викликати метод послуги? Його вводять в конструктор і доступно прямо в його корпусі. Чому він повинен зайти ngOnInit?
Сергій

@Sergey здебільшого за найкращі практики. Але для цього конкретного випадку я запустив профілювання процесора для обох способів виклику setPersistenceі виявив, що якщо це робиться в конструкторі, функціональні виклики все ще здійснюються в IndexedDB, тоді як якщо це робиться в ngOnInit, то в IndexedDB не було викликів, не точно. впевнений, чому все-таки
Джошуа Чан
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.