الجمعة، 20 ديسمبر 2013

How to catch memory leaks in an Angular application?

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 has a small memory leak and I've done my best to find it but I'm not able to do it. In the process I've managed to reduce the memory usage of my app, which is great.

Without doing anything else, every poll you can see a spike in the memory usage (that's normal) and then it should drop, but it's always increasing. I've changed the cleaning of the arrays from [] to array.length = 0 and I think I'm sure that references don't persist so it shouldn't be retaining any of this.

I've also tried this: https://github.com/angular/angular.js/issues/1522

But without any luck...

So, this is a comparison between two heaps:

Memory heap

Most of the leak seems to come from (array) which, if I open, are the arrays returned by the parsing of the API call but I'm sure they're not being stored:

This is basically the structure:

poll: function(service) { var self = this; log('Polling for %s', service); this[service].get().then(function(response) { if (!response) { return; } var interval = response.headers ? (parseInt(response.headers('X-Poll-Interval'), 10) || 60) : 60; services[service].timeout = setTimeout(function(){ $rootScope.$apply(function(){ self.poll(service); }); }, interval * 1000); services[service].lastRead = new Date(); $rootScope.$broadcast('api.'+service, response.data); });}

Basically, let's say I have a sellings service so, that would be the value of the service variable.

Then, in the main view:

$scope.$on('api.sellings', function(event, data) { $scope.sellings.length = 0; $scope.sellings = data;});

And the view does have an ngRepeat which renders this as needed. I spent a lot of time trying to figure this out by myself and I couldn't. I know this is a hard issue but, do anyone have any idea on how to track this down?

Edit 1 - Adding Promise showcase:

This is makeRequest which is the function used by the two services:

return $http(options).then(function(response) { if (response.data.message) { log('api.error', response.data); } if (response.data.message == 'Server Error') { return $q.reject(); } if (response.data.message == 'Bad credentials' || response.data.message == 'Maximum number of login attempts exceeded') { $rootScope.$broadcast('api.unauthorized'); return $q.reject(); } return response; }, function(response) { if (response.status == 401 || response.status == 403) { $rootScope.$broadcast('api.unauthorized'); }});

If I comment out the $scope.$on('api.sellings') part, the leakage still exists but drops to 1%.

PS: I'm using latest Angular version to date


View the original article here

ليست هناك تعليقات:

إرسال تعليق