Odkryłem, że użycie AngularFireAuthModule
from '@angular/fire/auth';
powoduje wyciek pamięci, który powoduje awarię przeglądarki po 20 godzinach.
Wersja:
Używam najnowszej wersji zaktualizowanej dzisiaj przy użyciu ncu -u dla wszystkich pakietów.
Kątowy ogień: "@angular/fire": "^5.2.3",
Firebase wersja: "firebase": "^7.5.0"
,
Jak powielać:
Zrobiłem minimalny powtarzalny kod w edytorze StackBliztz
Oto link do bezpośredniego przetestowania błędu test StackBlizt
Objaw:
Możesz sprawdzić, czy kod nic nie robi. To po prostu drukuje witaj świecie. Jednak pamięć JavaScript używana przez aplikację Angular zwiększa się o 11 kb / s (Chrome Task Manager CRTL + ESC). Po 10 godzinach pozostawiania otwartej przeglądarki używana pamięć osiąga około 800 mb (ślad zajmuje około dwa razy 1,6 Gb !)
W rezultacie w przeglądarce brakuje pamięci, a karta chrom ulega awarii.
Po dalszych badaniach przy użyciu profilowania pamięci chrome pod zakładką wydajności wyraźnie zauważyłem, że liczba słuchaczy rośnie o 2 co sekundę, a zatem stos JS odpowiednio rośnie.
Kod powodujący wyciek pamięci:
Odkryłem, że użycie AngularFireAuthModule
modułu powoduje wyciek pamięci, niezależnie od tego, czy jest wstrzykiwany do component
konstruktora, czy do 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){
}
}
Pytanie :
Może to być błąd w implementacji FirebaseAuth i już otworzyłem problem z Githubem, ale szukam obejścia tego problemu. Desperacko szukam rozwiązania. Nie mam nic przeciwko, nawet jeśli sesje między kartami nie są zsynchronizowane. Nie potrzebuję tej funkcji. Przeczytałem gdzieś to
jeśli nie potrzebujesz tej funkcji, wysiłki modularyzacyjne Firebase V6 pozwolą ci przejść na localStorage, który ma zdarzenia pamięci do wykrywania zmian między kartami, i ewentualnie zapewni ci możliwość zdefiniowania własnego interfejsu pamięci.
Jeśli to jedyne rozwiązanie, jak to wdrożyć?
Potrzebuję tylko rozwiązania, które zatrzyma ten niepotrzebny wzrost liczby słuchaczy, ponieważ spowalnia komputer i powoduje awarię mojej aplikacji. Moja aplikacja musi działać przez ponad 20 godzin, więc nie można jej już używać z powodu tego problemu. Desperacko szukam rozwiązania.
Odpowiedzi:
TLDR: Oczekiwany jest wzrost liczby słuchaczy i zostanie zresetowany po odśmiecaniu. Błąd powodujący przecieki pamięci w Firebase Auth został już naprawiony w Firebase v7.5.0, patrz # 1121 , sprawdź, czy
package-lock.json
używasz właściwej wersji. W razie wątpliwości zainstaluj ponowniefirebase
pakiet.Poprzednie wersje Firebase odpytywały IndexedDB poprzez łańcuch obietnic, który powoduje wycieki pamięci, patrz JavaScript Promise Leaks Memory
Naprawiono w kolejnych wersjach za pomocą nierekurencyjnych wywołań funkcji:
Jeśli chodzi o liniowo rosnącą liczbę słuchaczy:
Oczekuje się liniowego wzrostu liczby słuchaczy, ponieważ to właśnie robi Firebase, aby sondować IndexedDB. Jednak nasłuchiwacze zostaną usunięci, ilekroć GC chce.
Przeczytaj numer 576302: Nieprawidłowe wyświetlanie wycieku pamięci (nasłuchiwania i ładowanie)
Aby potwierdzić, że odłączone nasłuchiwania są gromadzone w pamięci, dodałem ten fragment kodu, aby wywrzeć nacisk na stos JS, zmuszając w ten sposób GC do uruchomienia:
Jak widać, odłączone odbiorniki są okresowo usuwane po uruchomieniu GC.
Podobne pytania o przepełnienie stosu i problemy z GitHub dotyczące liczby słuchaczy i wycieków pamięci:
źródło
this.auth.auth.setPersistence('none')
wngOnInit
zamiast konstruktora, aby wyłączyć funkcję utrwalania.ngOnInit
?setPersistence
i okazało się, że jeśli jest to zrobione w konstruktorze, wywołania funkcji są nadal wykonywane dla IndexedDB, podczas gdy jeśli jest zrobione wngOnInit
, nie wykonuje się żadnych wywołań dla IndexedDB, nie do końca jasne dlaczego