J'ai trouvé que l'utilisation de AngularFireAuthModule
from '@angular/fire/auth';
provoque une fuite de mémoire qui bloque le navigateur après 20 heures.
Version:
J'utilise la dernière version mise à jour aujourd'hui en utilisant ncu -u pour tous les packages.
Feu angulaire: "@angular/fire": "^5.2.3",
Version Firebase: "firebase": "^7.5.0"
,
Comment reproduire:
J'ai fait un code reproductible minimum sur l' éditeur StackBliztz
Voici le lien pour tester directement le bug StackBlizt test
Symptôme:
Vous pouvez vous vérifier que le code ne fait rien. Il imprime juste bonjour le monde. Cependant, la mémoire JavaScript utilisée par l'application angulaire augmente de 11 kb / s (Chrome Task Manager CRTL + ESC). Après 10 heures en laissant le navigateur ouvert, la mémoire utilisée atteint environ 800 Mo (l'empreinte mémoire est d'environ deux fois 1,6 Go !)
Par conséquent, le navigateur manque de mémoire et l'onglet Chrome se bloque.
Après une enquête plus approfondie en utilisant le profilage de la mémoire de chrome sous l'onglet performances, j'ai clairement remarqué que le nombre d'auditeurs augmente de 2 chaque seconde et donc le tas JS augmente en conséquence.
Code qui provoque la fuite de mémoire:
J'ai trouvé que l'utilisation du AngularFireAuthModule
module provoque la fuite de mémoire, qu'il soit injecté dans un component
constructeur ou dans un 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){
}
}
Question :
Cela pourrait être un bogue dans l'implémentation de FirebaseAuth et j'ouvre déjà un problème Github, mais je cherche une solution de contournement pour ce problème. Je cherche désespérément une solution. Cela ne me dérange pas même si les sessions entre les onglets ne sont pas synchronisées. Je n'ai pas besoin de cette fonctionnalité. J'ai lu quelque part
si vous n'avez pas besoin de cette fonctionnalité, les efforts de modularisation de Firebase V6 vous permettront de passer à localStorage qui a des événements de stockage pour détecter les changements de tableaux croisés, et vous donnera peut-être la possibilité de définir votre propre interface de stockage.
Si c'est la seule solution, comment l'implémenter?
J'ai juste besoin d'une solution qui arrête cette augmentation inutile de l'auditeur car elle ralentit l'ordinateur et plante mon application. Mon application doit fonctionner pendant plus de 20 heures, elle est donc désormais inutilisable en raison de ce problème. Je cherche désespérément une solution.
Réponses:
TLDR: l'augmentation du nombre d'écouteurs est un comportement attendu et sera réinitialisée lors du garbage collection. Le bogue qui provoque des fuites de mémoire dans Firebase Auth a déjà été corrigé dans Firebase v7.5.0, voir # 1121 , vérifiez votre
package-lock.json
pour confirmer que vous utilisez la bonne version. En cas de doute, réinstallez lefirebase
package.Les versions précédentes de Firebase interrogeaient IndexedDB via le chaînage Promise, ce qui provoque des fuites de mémoire, voir Promise Leaks Memory de JavaScript
Corrigé dans les versions ultérieures utilisant des appels de fonction non récursifs:
Concernant l'augmentation du nombre d'auditeurs de façon linéaire:
Le nombre d'écouteurs augmentant de manière linéaire est attendu car c'est ce que fait Firebase pour interroger IndexedDB. Cependant, les écouteurs seront supprimés chaque fois que le GC le souhaite.
Lire problème 576302: affichage incorrect de fuite de mémoire (écouteurs xhr et charge)
Pour confirmer que les écouteurs détachés sont récupérés, j'ai ajouté cet extrait pour faire pression sur le tas JS, forçant ainsi GC à se déclencher:
Comme vous pouvez le voir, les écouteurs détachés sont supprimés périodiquement lorsque le GC est déclenché.
Questions de stackoverflow similaires et problèmes GitHub concernant le nombre d'écouteurs et les fuites de mémoire:
la source
this.auth.auth.setPersistence('none')
aungOnInit
lieu du constructeur pour désactiver la persistance.ngOnInit
?setPersistence
et je constate que si cela est fait dans le constructeur, les appels de fonction sont toujours effectués vers IndexedDB, alors que si c'est fait dansngOnInit
, aucun appel n'a été fait vers IndexedDB, pas exactement mais pourquoi