मेमोरी आवंटन के +1 गीगाबाइट के साथ कोणीय फायरबेस ऐप 20 घंटे बाद क्रैश हो जाता है


13

मैंने पाया है कि का उपयोग कर AngularFireAuthModuleसे '@angular/fire/auth';एक स्मृति रिसाव है कि 20 घंटे के बाद ब्राउज़र दुर्घटनाओं का कारण बनता है।

संस्करण:

मैं सभी संकुल के लिए ncu -u का उपयोग करके आज अद्यतन किए गए नवीनतम संस्करण का उपयोग करता हूं।

कोणीय अग्नि: "@angular/fire": "^5.2.3",

फायरबेस संस्करण: "firebase": "^7.5.0" ,

कैसे पुन: पेश करें:

मैंने एक न्यूनतम प्रतिलिपि प्रस्तुत करने योग्य कोड बनाया StackBliztz संपादक

यहाँ सीधे StackBlizt परीक्षण बग का परीक्षण करने के लिए लिंक है

लक्षण:

आप खुद देख सकते हैं कि कोड कुछ नहीं करता है। यह सिर्फ हैलो वर्ल्ड को प्रिंट करता है। हालाँकि, Angular App द्वारा उपयोग की जाने वाली JavaScript मेमोरी 11 kb / s (क्रोम टास्क मैनेजर CRTL + ESC) से बढ़ती है। ब्राउज़र को खुला छोड़ने के 10 घंटे बाद, उपयोग की गई मेमोरी लगभग 800 mb तक पहुँच जाती है (मेमोरी फ़ुटप्रिंट लगभग 1.6 Gb है !)

नतीजतन, ब्राउज़र मेमोरी से बाहर चला जाता है और क्रोम टैब क्रैश हो जाता है।

प्रदर्शन टैब के तहत क्रोम की मेमोरी प्रोफाइलिंग का उपयोग करके आगे की जांच के बाद, मैंने स्पष्ट रूप से देखा कि श्रोताओं की संख्या में हर सेकंड 2 की वृद्धि होती है और इसलिए जेएस हीप तदनुसार बढ़ता है।

यहां छवि विवरण दर्ज करें

स्मृति रिसाव का कारण बनने वाला कोड:

मैंने पाया कि AngularFireAuthModule मॉड्यूल का उपयोग मेमोरी लीक का कारण बनता है चाहे वह एक componentकंस्ट्रक्टर में इंजेक्ट किया गया हो या एक में 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 modularization प्रयास आपको लोकलस्टोरेज पर स्विच करने की अनुमति देगा जिसमें परिवर्तन क्रॉस टैब्स का पता लगाने के लिए स्टोरेज इवेंट हैं, और संभवतः आपको अपने स्वयं के स्टोरेज इंटरफ़ेस को परिभाषित करने की क्षमता प्रदान करेगा।

यदि यह एकमात्र समाधान है, तो इसे कैसे लागू किया जाए?

मुझे बस किसी ऐसे समाधान की आवश्यकता है जो श्रोता की इस अनावश्यक वृद्धि को रोक दे क्योंकि यह कंप्यूटर को धीमा कर देता है और मेरे ऐप को क्रैश कर देता है। मेरे ऐप को 20 घंटे से अधिक समय तक चलने की आवश्यकता है, इसलिए इस मुद्दे के कारण अब यह अनुपयोगी है। मैं एक समाधान के लिए बेताब हूं।



मैं आपके उदाहरण पर आपके मुद्दे को फिर से प्रस्तुत करने में विफल रहा
सर्गेई मेल

@SergeyMell क्या आपने मेरे द्वारा StackBlitz पर पोस्ट किए गए कोड का उपयोग किया था?
टीएसआर

हाँ। दरअसल, मैं इसके बारे में बात कर रहा हूं।
सेर्गेई मेल

कोड डाउनलोड करने और इसे स्थानीय रूप से चलाने का प्रयास करें। मैं भी ड्राइव में इसे अपलोड सिर्फ मामले में drive.google.com/file/d/1fvo8eJrbYpZWfSXM5h_bw5jh5tuoWAB2/...
टीएसआर

जवाबों:


7

TLDR: श्रोता संख्या में वृद्धि व्यवहार की उम्मीद है और कचरा संग्रह पर रीसेट हो जाएगा। बग का कारण बनता है कि Firebase प्रमाणीकरण में मेमोरी लीक पहले से ही Firebase v7.5.0 में तय किया गया है, को देखने के # 1121 , अपने जाँच package-lock.jsonपुष्टि करने के लिए कि आप सही संस्करण का उपयोग कर रहे हैं। यदि अनिश्चित है, तो firebaseपैकेज को फिर से स्थापित करें ।

Firebase के पिछले संस्करण Promise chaining के माध्यम से IndexedDB मतदान कर रहे थे, जो मेमोरी लीक का कारण बनता है, जावास्क्रिप्ट का वादा लीक्स मेमोरी देखें

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 को पोल करने के लिए कर रहा है। हालांकि, जब भी जीसी चाहते हैं, श्रोताओं को हटा दिया जाएगा।

576302 अंक पढ़ें : गलत तरीके से मेमोरी दिखा रहा है (श्रोता xhr & load) लीक

वी 8 समय-समय पर माइनर जीसी करता है, जो ढेर के आकार की उन छोटी बूंदों का कारण बनता है। आप उन्हें वास्तव में लौ चार्ट पर देख सकते हैं। मामूली जीसी हालांकि सभी कचरा एकत्र नहीं कर सकते हैं, जो स्पष्ट रूप से श्रोताओं के लिए होता है।

टूलबार बटन मेजर जीसी को आमंत्रित करता है जो श्रोताओं को इकट्ठा करने में सक्षम है।

DevTools रनिंग एप्लिकेशन के साथ हस्तक्षेप नहीं करने की कोशिश करता है, इसलिए यह अपने आप पर जीसी को मजबूर नहीं करता है।


यह पुष्टि करने के लिए कि अलग किए गए श्रोता कचरा एकत्र कर रहे हैं, मैंने इस स्निपेट को जेएस के ढेर पर दबाव डाला, जिससे जीसी को ट्रिगर करने के लिए मजबूर किया गया:

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

श्रोताओं को कचरा एकत्र किया जाता है

जैसा कि आप देख सकते हैं, जीसी ट्रिगर होने पर अलग-अलग श्रोताओं को समय-समय पर हटा दिया जाता है।



श्रोता संख्या और मेमोरी लीक के बारे में इसी तरह के स्टैक्वेटफ्लो प्रश्न और GitHub मुद्दे:

  1. Chrome dev टूल के प्रदर्शन प्रोफाइलिंग परिणामों में श्रोता
  2. जावास्क्रिप्ट श्रोता बढ़ते रहते हैं
  3. स्मृति रिसाव के कारण सरल अनुप्रयोग?
  4. $ http 'GET' मेमोरी लीक (नहीं!) - श्रोताओं की संख्या (AngularJS v.1.4.7 / 8)

मैं 7.5.0 का उपयोग करके पुष्टि करता हूं और विभिन्न वातावरणों पर कई बार परीक्षण किया है। यहां तक ​​कि यह .auth.auth.setPersistence ('कोई नहीं') मेमोरी रिसाव को नहीं रोकता है। कृपया इसे खुद के द्वारा परीक्षण यहाँ कोड का उपयोग कर stackblitz.com/edit/angular-zuabzz
टीएसआर

आपके परीक्षण के चरण क्या हैं? क्या मुझे अपना ब्राउज़र क्रैश देखने के लिए इसे रात भर छोड़ने की आवश्यकता है? मेरे मामले में, जीसी किक के बाद श्रोता संख्या हमेशा रीसेट होती है और मेमोरी हमेशा 160mb पर वापस आ जाती है।
जोशुआ चान

@TSR कॉल this.auth.auth.setPersistence('none')में ngOnInitअक्षम हठ करने के लिए निर्माता की बजाय।
जोशुआ चान

@JoshuaChan सेवा की विधि को कॉल करने के लिए क्या फर्क पड़ता है? यह एक निर्माता में इंजेक्ट किया जा रहा है और यह शरीर में उपलब्ध है। इसमें क्यों जाना चाहिए ngOnInit?
सर्गेई

@ श्रेष्ठ अभ्यास के लिए ज्यादातर। लेकिन इस विशिष्ट मामले के लिए, मैंने कॉलिंग के दोनों तरीकों के लिए सीपीयू प्रोफाइलिंग को चलाया setPersistenceऔर पाया कि यदि यह कंस्ट्रक्टर में किया जाता है, तो फ़ंक्शन कॉल अभी भी IndexedDB को किए जाते हैं, जबकि यदि यह किया जाता है ngOnInit, तो IndexedDB के लिए कोई कॉल नहीं किया गया , बिल्कुल नहीं यकीन है कि हालांकि क्यों
यहोशू चान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.