I'm trying to find a solution for an AngularJS app memory leak. Because I'm new to the AngularJS world I don't really know where to start and where to correct and optimize my code.
I'm trying to give you a little description of the application first. Afterwards I'll post some memory statistics I could measure. I used three diagnostic tools to measure the used memory: Windows (7) Task Manager, Firefox about:memory and the Firefox Extension MemChaser.
Windows Task Manager
The memory used by Firefox increases by 50 - 100 MB per hour.
about:memory
Size (MB) 20 min diff Size (MB)
JS-Main-Runtime 32 36/+113% 68
JS-Main-Runtime-GC-Heap-Committed 20 27/+135% 47
Heap-Allocated 54 29/+54% 83
Heap-Committed 63 28/+44% 91
JS-GC-Heap 31 26/+84% 57
Private 156 58/+37% 214
Resident 175 62/+35% 237
VSize 509 86/+17% 595
MemChaser 0.5.2.1
12:17 12:27 12:57 13:17
Resident (MB) 140 164 243 270
iGC (ms) 42 24 40 42
CC (ms) 3 53 206 286
Resident: Memory used by the process that is present in the physical memory. iGC: Duration of the last garbage collector activity. CC: Duration of the last cycle collector activity.
These results are pretty dramatic and it seems like the cycle collector gives the best hint. If I run my app without the view (just the Ajax request) nothing dramatic happens. If I disable the dynamic template loading there is no distinctive difference to the version with dynamic templates. So it seems like these two topics aren't the cause.
My idea: with every Ajax request new scopes and DOM nodes are created. The DOM nodes may be ereased afterwards but the scopes with there data will propably still be in the memory. Is that a possible scenario and a cause for my memory leak?
So how should I properly work with AngularJS directives, scopes and bindings to avoid memory leaks like these?
I would be very very delighted about any help.
Tobias
I use the AngularJS Batarang Chrome extension to assist in debugging these type of issues. Monitor the Models and Performance tabs of this extension to pick up on any dangling or leaking scopes. Make sure when you do not need a specific scope any more that your $destroy it. E.g. see how ngRepeat does this.
From the documentation:
$destroy()
Removes the current scope (and all of its children) from the parent scope. Removal implies that calls to $digest() will no longer propagate to the current scope and its children. Removal also implies that the current scope is eligible for garbage collection.
The $destroy() is usually used by directives such as ngRepeat for managing the unrolling of the loop. Just before a scope is destroyed, a $destroy event is broadcasted on this scope.
Application code can register a $destroy event handler that will give it a chance to perform any necessary cleanup. Note that, in AngularJS, there is also a $destroy jQuery event, which can be used to clean up DOM bindings before an element is removed from the DOM.
And
$destroy() must be called on a scope when it is desired for the scope and its child scopes to be permanently detached from the parent and thus stop participating in model change detection and listener notification by invoking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With