How to catch memory leaks in an Angular application?

前端 未结 2 1805
滥情空心
滥情空心 2020-12-04 11:17

I have a webapp written in AngularJS which basically polls an API to two endpoints. So, every minute it polls to see if there is anything new.

I discovered that it h

相关标签:
2条回答
  • 2020-12-04 11:32

    The standard browser way to fix memory leaks is to refresh the page. And JavaScript garbage collection is kind of lazy, likely banking on this. And since Angular is typically a SPA, the browser never gets a chance to refresh.

    But we have 1 thing to our advantage: Javascript is primarily a top-down hierarchial language. Instead of searching for memory leaks from the bottom up, we may be able to clear them from the top down.

    Therefore I came up with this solution, which works, but may or may not be 100% effective depending on your app.

    The Home Page

    The typical Angular app home page consists of some Controller and ng-view. Like this:

    <div ng-controller="MainController as vm"> <div id="main-content-app" ng-view></div> </div>

    The Controller

    Then to "refresh" the app in the controller, which would be MainController from the code above, we redundantly call jQuery's .empty() and Angular's .empty() just to make sure that any cross-library references are cleared.

    function refreshApp() {
    var host = document.getElementById('main-content-app');
    if(host) {
        var mainDiv = $("#main-content-app");
        mainDiv.empty();
        angular.element(host).empty();
    }
    }
    

    and to call the above before routing begins, simulating a page refresh:

    $rootScope.$on('$routeChangeStart',
    function (event, next, current) {
        refreshApp();
    }
    );
    

    Result

    This is kind of a hacky method for "refreshing the browser type behavior", clearing the DOM and hopefully any leaks. Hope it helps.

    0 讨论(0)
  • 2020-12-04 11:33

    And the answer is cache.

    Heap Snapshot analysis

    I don't know what it is, but this thing grows. It seems to be related to jQuery. Maybe it's the jQuery element cache. Do you by any chance apply a jQuery plugin on one or more elements after every service call?

    Update

    The problem is that HTML elements are added, processed with jQuery (e.g. via the popbox plugin), but either never removed at all or not removed with jQuery. To process in this case means stuff like adding event handlers. The entries in the cache object (whatever it is for) do only get removed if jQuery knows that the elements have been removed. That is the elements have to be removed with jQuery.

    Update 2

    It's not quite clear why these entries in the cache haven't been removed, as angular is supposed to use jQuery, when it's included. But they have been added through the plugin mentioned in the comments and contained event handlers and data. AFAIK Antonio has changed the plugin code to unbind the event handlers and remove the data in the plugin's destroy() method. That eventually removed the memory leak.

    0 讨论(0)
提交回复
热议问题