Is this AJAX sample a memory leak?

Consider this example of a fairly standard method in Angular Js that updates a view:

$scope.fetchResults = function() { // Some local variable that will cause creation of closure var hugeData = serviceX.getMilionRecords(); // Any call to any resource with success and error handlers. $http({ method: "GET", url: "/rest-api/bulk-operation-x", params: { someParam: hugeData.length } }).success( function () { var length = hugeData.length; $scope.reportToUser("Success, that was " + length + " records being processed!"; }).error( function () { var length = hugeData.length; $scope.reportToUser("Something went wrong while processing " + length + " records... :-("; }); }; 

This is, of course, a hypothetical example, but it shows a pattern that can be described as reusing local variables from AJAX callbacks.

Of course, in both handlers ( success and error ) we create a closure on hugeData that directly refers to callback handlers.

My question is: since the result of an AJAX call can only be success or failure, will reusing this code cause a memory leak in time? I would answer yes, but I could not reliably prove this in my local tests.

I would like a more experienced guru to explain this to me. I would really like the answer from anyone who works with Angular on a daily basis, but any jquery answers are also welcome.

+6
source share
1 answer

You will have a memory leak as soon as you return the result of calling $http() (or any other object or function that has access to hugeData ) to the outside of fetchResults .

With your code, nothing is displayed directly outside of fetchResults , and the result of calling $http() will live until it succeeds or fails, and then calls the corresponding callback, finally getting GC'ed.

See info: http://jibbering.com/faq/notes/closures/#clIdRes

As @ ŁukaszBachman notes, this does not guarantee that there are no memory leaks. Any freezing link to your large object or your callback with a large object in scope will cause grief.

So, consider the implementation of $q ( $http based on $q ).

If you check https://github.com/angular/angular.js/blob/master/src/ng/q.js#L191 , you will see that the deferred resolve() method first copies the list of registered callbacks to the local variable for the method:

 var callbacks = pending; 

subsequently invalidates the outer pending (which was defined at defer level)

 pending = undefined; 

then at the next tick, callbacks are executed. This can be complicated by the fact that the callback argument can be delayed (adding extra delay to the execution), but at best you can get into an infinite loop. (And this is not funny!). If you are lucky enough to get into a loop, then at some point the callback array is exhausted, and then there is no link to the callback list, so it is available for GC.

But.

Everything can go wrong if you force them.

You can use arguments.callee inside the callback.

You can also drink beer on the keyboard.

If you jump out of the window, if you do not live on the ground floor, you will probably be hurt.

Happy EcmaScripting!

+4
source

Source: https://habr.com/ru/post/946495/


All Articles