Google Chrome has run out of memory - Memory Leak Javascript

1

Good morning,

I have a website that should always be running on a monitor in the form of information for people who enter the company to see news, economic data, etc.

The main page manages the rest of the screens that are shown creating a slider effect to the left adding iframes and eliminating them.

With the first load and with each complete round an object called ScreenManager makes a query by ajax to get what screens it should show and what time it gives to each one.

This object is responsible for creating iframe elements for the current page and the next one, in addition to inserting them in the corresponding container to perform the slide effect.

The fact is that it works quite well for 1 full day or so, but when we return to work the next day we find a default Google Chrome page indicating that it has run out of memory.

I understand that the error must be on the main page that is where the ScreenManager object is executed, which is what the Ajax does.

I chose the use of iframes since you can configure two screens in a row with different language (and the javascript code of each screen was pasted with its version in another language in the case of going one after the other) and also because I understood that when removing the iframes the memory used by the sub-screens would be released immediately.

Does anyone have any idea how to optimize the use of memory? Should I assign the variable Screens to null before doing the Ajax to clean it? Does the use of iframes significantly increase long-term memory use?

To give you a clearer idea of the code I leave an example: Home.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF8"/>
    <style>
    #Mask{position: absolute; width: 100%; height: 100%; top: 0px; left: 0px; background-color:         transparent; z-index: 1000000;}
</style>
</head>
<body>
    <div id="main"></div>
    <div id="Mask">
        <!-- Zone to control key events , because we lose the events in iframes.pages -->
    </div>
    <!-- Scripts -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
<script>
$.fn.ScreenManager = function (options) {

    /**
     * Helpper var to this 
     */
    var PL = this;

    /**
     * RebindData
     */
    this.RebindData = function (firstTime) { 
        /** the original code is ajax request **/
        PL.DataManager.CurrentPage = 0;
                PL.NextScreenLoad = true;
        /** fake Screen Array Objects **/
                PL.DataManager.ScreensData = [
                {
                  Title:"Wikipedi Javascript",
                  Controller:'https://es.wikipedia.org/wiki/JavaScript',
                  TimeToNext:10 //seconds
                },
                {
                  Title:"wikipedia home",
                  Controller:'https://es.wikipedia.org/wiki/Wikipedia:Portada',
                  TimeToNext:10 //seconds
                }];
                if (firstTime)
                    PL.ChargeFirstScreen();
                else { 
                    PL.ChargeScreen();
                }
    }

    this.ChargeFirstScreen = function () { 
        PL.NextScreenLoad = false;

        var screen = PL.DataManager.ScreensData[0];
        $(document).prop('title', screen.Title); 
         
        var firstScreen = $(PL.DataManager.PageHTML);
        PL.PrevTitle = screen.Title;

        firstScreen.attr("src", screen.Controller);
        firstScreen.addClass('current');
        firstScreen.css('left','0px');
        firstScreen.load(function () {
            try {
                //this is for prevent init screen efects on document ready 
                //$(PL).find('iframe.current')[0].contentWindow.InitOnCharge();
            } catch (e) {
                window.location.href = window.location.href;
            } 
        });

        $(PL).append(firstScreen); 

        if (!PL.CheckIfRebind(screen, true)) {
            PL.DataManager.CurrentPage = PL.WhatIsTheNext();
            var screen2 = PL.DataManager.ScreensData[PL.DataManager.CurrentPage];
            PL.PrintTheNextScreen(screen2, PL.WhatIsTheNext());
            PL.TransitionTimeOut = setTimeout(function() {
                PL.ChargeScreen();
            }, screen.TimeToNext * 1000);

        }  
    }

    this.CheckIfRebind = function (screen, firstTime) {

        if (PL.WhatIsTheNext() == 0) {
            if (firstTime) {
                PL.PrintTheNextScreen(screen,0);
                PL.TransitionTimeOut = setTimeout(function () {
                    PL.RebindData(false);
                }, screen.TimeToNext * 1000);
            }
            return true;
        } else {
            return false;
        }
    }

    this.PrintTheNextScreen = function (screen,n) {
        var nextScreen = $(PL.DataManager.PageHTML);
        PL.PrevTitle = screen.Title;
        nextScreen.attr("src", screen.Controller);
        nextScreen.addClass('next');
        nextScreen.load(function () {
            PL.NextScreenLoad = true;
        });
        $(PL).append(nextScreen);

    }

    this.NextScreen = function (screen) {
        //clean the  global vars 
        PL.NextScreenLoad = false; 

        $(document).prop('title', PL.PrevTitle);

        PL.PrevTitle = screen.Title;

        $(PL).find('.current').animate({
            left: '-100%'
        }, 'slow', function () {
            $(this).remove();
        });

        $(PL).find('.next').animate({
            left: '0%'
        }, 'slow', function () {

            $(this).removeClass('next').addClass('current');

            try {
               //this is for prevent init screen efects on document ready 
                //$(PL).find('iframe.current')[0].contentWindow.InitOnCharge();
            } catch (e) {
                window.location.href = window.location.href;
            }
            

            if (PL.WhatIsTheNext() == 0) {
                PL.DataManager.CurrentPage =  PL.WhatIsTheNext();
                PL.PrintTheNextScreen(PL.DataManager.ScreensData[PL.DataManager.CurrentPage], PL.DataManager.CurrentPage);
                PL.TransitionTimeOut = setTimeout(function () {
                    PL.RebindData(false);
                }, screen.TimeToNext * 1000);

            } else {
                PL.DataManager.CurrentPage ++;
                PL.PrintTheNextScreen(PL.DataManager.ScreensData[PL.DataManager.CurrentPage], PL.DataManager.CurrentPage);
                PL.TransitionTimeOut = setTimeout(function() {
                    PL.ChargeScreen();
                }, screen.TimeToNext * 1000);
            }
        });
         
    }

    this.WhatIsTheNext = function() {
        if (PL.DataManager.CurrentPage == PL.DataManager.ScreensData.length - 1)  
            return 0; 
        else return PL.DataManager.CurrentPage+1;
    }

    this.WhatIsThePrev = function () {
        if (PL.DataManager.CurrentPage != 0)
            return PL.DataManager.CurrentPage -1;
        else return PL.DataManager.ScreensData.length-1;
    }

    this.ChargeScreen = function () { 
        if (PL.NextScreenLoad) {
                PL.NextScreen(PL.DataManager.ScreensData[PL.DataManager.CurrentPage]);
        }
        else
            PL.TransitionTimeOut = setTimeout(function () {
                PL.ChargeScreen();
            }, 10); 
    }

    /**
     * Initialize function
     */ 
    this.Initialize = function () { 
        if (this.Select != '' || this.Select != null) {
            $(this).css({
                position: 'absolute',
                width: '100%',
                height: '100%',
                top: '0px',
                left: '0px',
                overflow: 'hidden'
            });

            this.RebindData(true); 
        }
        else
            alert("Hay un error en el parametro Select de Screen Manager");
    }
    /**
     * Properties
     */
    this.Select = options.Select;
    this.TransitionTimeOut = false;
    this.NextScreenLoad = false; 
    this.PrevTitle = null; 

    //default Configuration
    this.DataManager = {
        ScreenTimeToNext: 30, 
        CurrentPage: 0,
        ScreensData: [],
        PageHTML: '<iframe style="position: absolute;width: 100%; height: 100%;left:100%;top:0px;border:none;" class="page" />'
    } 
    //run Init
    this.Initialize();

    //set this plugin to data element
    this.data('ScreenManager', this); 

    //return this plugin
    return this;
}
</script>
    <script>
      var ScreenManager = null;
      $(document).ready(function() {
        ScreenManager = $('#main').ScreenManager({
            Select: 'UrlToGetScreensJson', Callback: "InitOnCharge"
        });
        $(document).keydown(function(e) {
            if (e.keyCode == 39) {
                clearInterval(ScreenManager.TransitionTimeOut);
                ScreenManager.ChargeScreen();
            }
        });
      });
    </script> 
</body>
</html>

ScreenManager.js

Thanks and best regards.

    
asked by Angel Fraga 28.11.2016 в 11:40
source

1 answer

1

I think more code is needed to give you a firm answer:

  • Check the setTimeout you're using.
  • Delete the old items (I only see that you are doing append , but I do not see where you are doing the remove or the empty of the parent).
  • Avoid storing DOM elements in variables that you will not clean (e.g. this.$el = $('.selector') .) If there is a reference to a DOM element, even though it has been removed from the DOM, it will remain in memory.
  • Regarding your question about the iframes, in stackoverflow (English) I found this article in which you recommend that you reload the iframe before deleting it:

    var frame = document.getElementById("myframe");
    frame.src = "about:blank";
    

    And that iframe itself removes the data it can store (references included):

    window.onbeforeunload = function(){
        $(document).unbind().die();    //remove listeners on document
        $(document).find('*').unbind().die(); //remove listeners on all nodes
        //clean up cookies
        /remove items from localStorage
    }
    

    I have never used iframes intensively, it seems an interesting case and I will follow it until you solve it:)

        
    answered by 30.11.2016 в 09:57