Ứng dụng Angular Firebase gặp sự cố sau 20 giờ với phân bổ bộ nhớ +1 gigabyte


13

Tôi thấy rằng việc sử dụng AngularFireAuthModuletừ '@angular/fire/auth';gây ra rò rỉ bộ nhớ đã làm sập trình duyệt sau 20 giờ.

Phiên bản:

Tôi sử dụng phiên bản mới nhất được cập nhật hôm nay bằng cách sử dụng ncu -u cho tất cả các gói.

Lửa góc: "@angular/fire": "^5.2.3",

Phiên bản hỏa lực : "firebase": "^7.5.0",

Cách sinh sản:

Tôi đã tạo mã có thể tái tạo tối thiểu trên trình soạn thảo StackBliztz

Dưới đây là liên kết để kiểm tra lỗi trực tiếp Kiểm tra StackBlizt

Triệu chứng:

Bạn có thể tự kiểm tra xem mã không làm gì cả. Nó chỉ in thế giới xin chào. Tuy nhiên, bộ nhớ JavaScript được sử dụng bởi Ứng dụng Angular tăng thêm 11 kb / s (Trình quản lý tác vụ Chrome CRTL + ESC). Sau 10 giờ để trình duyệt mở, bộ nhớ được sử dụng đạt xấp xỉ 800 mb (dung lượng bộ nhớ khoảng hai lần 1.6 Gb !)

Hậu quả là trình duyệt hết bộ nhớ và tab chrome gặp sự cố.

Sau khi điều tra thêm bằng cách sử dụng cấu hình bộ nhớ của chrome trong tab hiệu suất, tôi nhận thấy rõ rằng số lượng người nghe tăng 2 mỗi giây và do đó, heap JS tăng theo.

nhập mô tả hình ảnh ở đây

Mã gây rò rỉ bộ nhớ:

Tôi thấy rằng việc sử dụng AngularFireAuthModule mô-đun gây ra rò rỉ bộ nhớ cho dù nó được đưa vào trong một hàm componenttạo hoặc trong một 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){

  }
}

Câu hỏi :

Nó có thể là một lỗi trong quá trình triển khai FirebaseAuth và tôi đã mở một vấn đề Github, nhưng tôi đang tìm cách giải quyết cho vấn đề này. Tôi đang tuyệt vọng cho một giải pháp. Tôi không bận tâm ngay cả khi các phiên trên các tab không được đồng bộ hóa. Tôi không cần tính năng đó. Tôi đọc ở đâu đó

nếu bạn không yêu cầu chức năng này, các nỗ lực mô đun hóa Firebase V6 sẽ cho phép bạn chuyển sang localStorage có các sự kiện lưu trữ để phát hiện các thay đổi của các tab chéo và có thể sẽ cung cấp cho bạn khả năng xác định giao diện lưu trữ của riêng bạn.

Nếu đó là giải pháp duy nhất, làm thế nào để thực hiện điều đó?

Tôi chỉ cần bất kỳ giải pháp nào ngăn chặn sự gia tăng người nghe không cần thiết này vì nó làm chậm máy tính và làm hỏng ứng dụng của tôi. Ứng dụng của tôi cần chạy hơn 20 giờ để không sử dụng được do vấn đề này. Tôi đang tuyệt vọng cho một giải pháp.



Tôi đã thất bại trong việc tái tạo vấn đề của bạn trên ví dụ của bạn
Sergey Mell

@SergeyMell Bạn có sử dụng mã tôi đã đăng trên StackBlitz không?
TSR

Đúng. Thật ra, tôi đang nói về nó.
Serge Mell

Hãy thử tải mã và chạy nó cục bộ. Tôi cũng đã tải nó lên trong ổ đĩa chỉ trong trường hợp drive.google.com/file/d/1fvo8eJrbYpZWfSXM5h_bw5jh5tuoWAB2/
TSR

Câu trả lời:


7

TLDR: Tăng số lượng người nghe là hành vi dự kiến ​​và sẽ được đặt lại trên Bộ sưu tập rác. Lỗi gây rò rỉ bộ nhớ trong Firebase Auth đã được sửa trong Firebase v7.5.0, xem # 1121 , kiểm tra package-lock.jsonđể xác nhận rằng bạn đang sử dụng đúng phiên bản. Nếu không chắc chắn, hãy cài đặt lại firebasegói.

Các phiên bản trước của Firebase đã bỏ phiếu IndexedDB thông qua chuỗi Promise, gây rò rỉ bộ nhớ, xem Bộ nhớ rò rỉ Promise của 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();

Đã sửa lỗi trong các phiên bản tiếp theo sử dụng các lệnh gọi hàm không đệ quy:

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();


Về số lượng người nghe tăng tuyến tính:

Số lượng người nghe tăng tuyến tính được mong đợi vì đây là những gì Firebase đang làm để thăm dò IndexedDB. Tuy nhiên, người nghe sẽ bị loại bỏ bất cứ khi nào GC muốn.

Đọc vấn đề 576302: rò rỉ bộ nhớ (người nghe xhr & tải) không chính xác

V8 thực hiện GC nhỏ theo định kỳ, gây ra những giọt nhỏ kích thước heap. Bạn thực sự có thể nhìn thấy chúng trên biểu đồ ngọn lửa. Tuy nhiên, các GC nhỏ có thể không thu thập tất cả rác, điều này rõ ràng xảy ra cho người nghe.

Nút thanh công cụ gọi ra Major GC có khả năng thu thập người nghe.

DevTools cố gắng không can thiệp vào ứng dụng đang chạy, vì vậy nó không ép buộc chính nó.


Để xác nhận rằng các trình nghe tách rời là rác được thu thập, tôi đã thêm đoạn mã này để gây áp lực cho đống JS, do đó buộc GC phải kích hoạt:

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

Người nghe là rác thu thập

Như bạn có thể thấy, các trình nghe tách rời được loại bỏ định kỳ khi kích hoạt GC.



Các câu hỏi stackoverflow tương tự và các vấn đề GitHub liên quan đến rò rỉ số lượng người nghe và bộ nhớ:

  1. Trình nghe trong kết quả cấu hình hiệu suất của công cụ Chrome dev
  2. Trình nghe JavaScript tiếp tục tăng
  3. Ứng dụng đơn giản gây rò rỉ bộ nhớ?
  4. $ http 'GET' rò rỉ bộ nhớ (KHÔNG!) - số lượng người nghe (AngularJS v.1.4.7 / 8)

Tôi xác nhận sử dụng 7.5.0 và đã thử nghiệm nhiều lần trên các môi trường khác nhau. Ngay cả this.auth.auth.setPersistence ('none') cũng không ngăn chặn rò rỉ bộ nhớ. Vui lòng tự kiểm tra nó bằng cách sử dụng mã tại đây stackblitz.com/edit/angular-zuabzz
TSR

các bước kiểm tra của bạn là gì? Tôi có cần để nó qua đêm để xem trình duyệt của tôi bị sập không? Trong trường hợp của tôi, số người nghe luôn đặt lại sau khi cú đá GC vào và bộ nhớ luôn trở về 160mb.
Joshua Chan

Gọi @TSR this.auth.auth.setPersistence('none')trong ngOnInitthay vì các nhà xây dựng để vô hiệu hóa bền bỉ.
Joshua Chan

@JoshuaChan có vấn đề gì khi gọi phương thức dịch vụ không? Nó được tiêm vào một nhà xây dựng và có sẵn ngay trong cơ thể của nó. Tại sao nó nên đi vào ngOnInit?
Serge

@Sergey chủ yếu để thực hành tốt nhất. Nhưng đối với trường hợp cụ thể này, tôi đã chạy cấu hình CPU cho cả hai cách gọi setPersistencevà thấy rằng nếu nó được thực hiện trong hàm tạo, các lệnh gọi hàm vẫn được thực hiện cho IndexedDB, trong khi nếu nó được thực hiện ngOnInit, thì không có cuộc gọi nào được thực hiện cho IndexedDB, không chính xác chắc chắn tại sao mặc dù
Joshua Chan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.