-
Notifications
You must be signed in to change notification settings - Fork 27.5k
Using $timeout causes a memory leak #1522
Comments
we don't call settimeout with strings anywhere, so something else must be going on. how did you diagnose the code above as leaky? do you see retained objects or something that could pinpoint the cause? |
I kept receiving a chrome aww snap. After finding out what an aww snap It showed the heap size growing as time passed and garbage collection Sorry for the lack of technical terms, I've only delved into this the last
|
I happened upon this GitHub issue while diagnosing my own, similar problem. The code I was using was: tick = ->
$scope.time = ServerTime() // returns a promise based on some calculations
$timeout tick, 5000
tick() I noticed that after a while, I would get the "Aww snap" Chrome message, and after a while I noticed I could make it happen much faster by setting a a lower timeout; using a value of After some fiddling, I changed the code to: tick = ->
$scope.time = ServerTime() // returns a promise based on some calculations
$scope.$apply()
setTimeout tick, 5000
tick() And I've found it works much better (even with a low timeout). I hope this helps; please let me know if I can provide additional information. |
Could you provide a working demo of this problem? This simple On 12 November 2012 00:24, Brandon Tilley notifications@github.com wrote:
|
I wonder if this is related to #1313 |
I can't repro this either. Anybody can provide more info? Ideally a working fiddle/plunker/html that leaks. |
I've done some digging in the Chrome inspector, and it does look like my leak is related to the promises I use in |
I was using angular 1.0.1 and initially it looked like this http://plnkr.co/edit/upkYuG was a replication of the problem but it doesn't seem to increase beyond a certain size. You could potentially take a look at my github to see where it was there jaitaiwan/CPresent pub-src/assets/js/compiled/presenter.coffee TL;DR: Same code in my app as in plunkr http://plnkr.co/edit/upkYuG and can't replicate. |
@BinaryMuse any luck? example code would be awesome. if you can't repro it outside of your app having a heap snapshot would help too, though that's far from ideal, but definitely better than nothing. cc: @jaitaiwan |
Unfortunately, I don't have a specific commit I can checkout to reproduce the issue, without re-factoring the commit to remove the other bugs which also prevented proper garbage collection. Unless of course you don't mind having a heap with that stuff in there as well? |
@jaitaiwan Can't you just swap setTimeout for $timeout and see if you can still reproduce the problem? |
Here is a heap snapshot. https://docs.google.com/open?id=0B3xElvhp0JIhUW9jbUxzQkF0Ujg |
This example here causes a rapid memory leak in both Chrome and FF (OS X) for me: http://plnkr.co/edit/b25pmGVQyZJatuCwIRWU I could only reproduce the leak when running the timeout inside a service, rather than in a controller. Replacing $timeout with window.setTimeout stops the leak. |
I was able to reproduce the issue with the example that @petebacondarwin posted at http://plnkr.co/edit/wZyC4w by changing app.js line 11 to: return $timeout(tick, 1) This is what the code produced by the CoffeeScript @BinaryMuse posted does. In CoffeeScript, adding a line containing just "null" to the end of the method (to make it return null) avoids the problem. |
@Cufeadir Aha! Thank you -- I should have realized this was the problem, as @IgorMinar As mentioned by @Cufeadir, simply adding |
What an insidious problem. We just encountered the same issue. It's very natural to write re-arming timers in CoffeeScript this way, and the interaction of CoffeeScript's default returns and Angular's $timeout returning a promise is absolutely non-obvious. We tried to figure it out from heapdumps, which show a rapidly growing 'pending' array for the 'defer' object associated with the $timeout, but didn't succeed until we found this post. It's not only a memory leak, but will eat up CPU time because there are (n-1) calls to defer.promise.then at the n-th invocation of the timeout. |
I've encountered the same issue. Using Replacing $timeout(recur, 1000) with setTimeout ->
$scope.$apply -> recur()
, 1000 seems to fix the issue. |
Just finished my memory leak hunt and finally found this issue. Based on some experiments the problem seems to be solved by NOT returning the recursive call (which cofeescript does by default). this seems to work ok:
this results in memory leak:
|
@xonix: that's what @Cufeadir said and @BinaryMuse confirmed. You can write either 'return', 'null', or 'return null' - they'll all work so that the coffeescript compiler will produce code that will not return the return value of $timeout, which is what's causing the leak. |
Can someone provide a PR doc update to |
I can't reproduce the issue on Chrome v50.0.2661.102 - Windows 10 - Angular v1.5.5. |
@ljmagiera Have you managed to solve your problem, I am having the same issue. I have a $http promise inside a $timeout and I am getting memory leak. My app is a single page and single controller app so $timeout.cancel on $scope.$destroy is not much of a help |
@rajdeol, if you can provide a reproduction of the leak, we can investigate and (if it turns out to be an Angular issue) fix it. Just saying... 😃 |
@gkalpak I have created the plunker http://plnkr.co/edit/2HprjNPUU9IrBQxdw1Z0?p=preview What I have noticed further is:
Please suggest if anything can be done to reduce the memory piling up, it freezes the client machine before the garbage collection kicks in. |
@rajdeol what you see is normal and not indicative of a memory leak. A memory leak occurs if objects are kept alive in a way that prevents garbage collection from freeing them. In this case, you would not see a decrease in used memory after a garbage collection occurs. |
@godmar Thanks for the clarification, but my issue is memory is keep on piling and garbage collection does not fire. Try and profile the plunker I have shared in the chrome dev-tools. Timeline will show you the memory build up. |
@rajdeol: As @godmar said, it is normal (and expected) that memory builds up during an application's lifetime (and reduced periodically with garbage collection). I doubt that just building up GC-able memory freezes the client's browser (and if it does, then it sounds like a browser issue). I don't think there is anything to do in Angular. If you feel Angular timeouts or promises could be more efficient in terms of the memory pressure they create, please post a minimal demo (without non-Angular dependencies) and the steps needed to reproduce the unnecessarily high memory built-up. |
After much fun learning about memory leaks and how to use chrome's profiler and timeline. I finally found out the cause of my memory leak.
It appears that natively, a memory leak is created when passing a string to
setTimeout
instead of a function reference: http://pavel.kuzub.com/settimeout-memory-leakAn example of the code I was using that was faulty:
changing
to
Fixed the issue.
I assume that there is probably a call to
$scope.$eval
somewhere in$timeout
which is what is causing the issue.The text was updated successfully, but these errors were encountered: