Understanding AngularJS and Google Chrome memory management - angularjs

i was wondering why - even on the simple SPA application with AngularJS there seems to be a DOM leakage. I may be misinterpreting this but the way I look at this is that DOM elements allocated are not being released properly.
The procedure to reproduce is as follows:
navigate to the page on the screenshot with simple AngularJS application
turn on timeline recording in developer tools
force garbage collection
add an item, and then remove it
force garbage collection
repeat last two steps for atleast 3 times
On the screenshot you can see that after you add an item and remove it there seems to be two more DOM elements more after garbage collection(jump from 502 to 504 DOM elements).
I was hoping that someone could shed some light on this before i get deeper on investigating what is happening. Reason for this test was more complicated AngularJS SPA that I am working on and which also seems to leak memory.

I'm doing a similar thing now. What I've noticed is a couple of things:
1) look at any usage of $(window).fn() -- where fn is any of the functions on the window object; if you're doing that more than once you're adding multiple event handlers to the global object which causes a memory leak
2) $rootScope.$watch() -- similarly, if you're doing this more than once (say, when loading a directive) then you're adding multiple handlers to the global object
3) In my tests (where I go back and forth between two pages) it seems that chrome consumes a large amount of memory (in my case, almost 1GB) before garbage collection kicks in. Maybe when you click the "garbage collection" chrome is not actually doing a GC? Or it's GC for javacsript but not for dom elements?
4) If you add an event handler to the dom element, then remove it from the dom, the handlers never get GC'ed.

Related

How React Virtual Dom is faster? At the end of all its going to hit call browser API to update the real DOM

I read through all the articles in internet. Still i cant understand and mind is puzzling me questions again and again that is
At the end of all the virtual DOM it is going to call the browser API to update the real DOM then how come it will be faster?
Is virtual DOM of React have special access to browsers core API's to modify?
I cant understand? Any resolves this questions Thanks in advance
Here is a talk given circa 2013 (v0.4.0) by the two guys behind React. They describe exactly how it works. Unlike data binding and dirty checking (Angular, etc.) React uses one render method that's called recursively. It then generates a long string that is a representation of the DOM. The concept is actually really simple.
https://www.youtube.com/watch?v=XxVg_s8xAms
Yes, you are right finally the task is to update real dom but the virtual dom comes in picture before updating the real dom. how ?
Suppose you want to update any/many element(s) in Dom tree element then there should be a mechanism to find which element(s) needs to be updated in real dom i.e the browser screen we see.
So this dom finding algorithm executed in virtual dom i.e a javascript copy of real dom(a html dom tree).
React creates two virtual dom, one from existing real dom and other from the changes made. These two virtual dom comparison saves time. The difference of this comparison used for updating real dom.
At the end of all the virtual DOM it is going to call the browser API to update the real DOM then how come it will be faster?
Any speed benefits come from minimizing the number of DOM manipulations that are needed and doing them all at once. The virtual DOM is react's way of calculating the minimum set of changes.
Here's what i mean by calculating the minimum set of changes: The page starts off looking one way, and then you want to make it look some other way. To get there, you're going to need to make one or more changes to the DOM, but there are many different ways you could do it.
A really bad way to update the page would be to wipe the entire document, and then rebuild every single element from scratch. Most likely though, you can reuse most of the page and just make a few updates to select parts of the page: add a div here; update a property there, add an event listener there. That's what you want: a small number of steps that take the old page and turn it into the new page.

memory increment of the application in the browser while running it for several hour

I am stuck with the memory increment of my application and as it is single page I can't even reload it. After running my application for around 5-6 hour memory size is reaching around 600mb from initial loading i.e 120mb and we did some fixed for this like making the ref to null in the componentWillunMount() and memory has reduced to 400 mb after the same testing for same time but still I can see there are lot many detached element, definitely it caused by some other parts of the code, in the snapshot file which we can take from chrome inbuilt functionality. So is there any way that I can remove all the detached-element while leaving the certain page or why don't browser removed this from memory as the detached-element is retaining some size of the memory ?
DOM node can only be garbage collected when there are no references to it from either the page's DOM tree or JavaScript code.
I suggest you take a look at your code and see if there are functions running not when you want it. If you use react or similar frameworks, you have to be careful with their lifecycle (important!).
Also here https://developers.google.com/web/tools/chrome-devtools/memory-problems/
There are many useful information, such as
- Investigate memory allocation by function
- Spot frequent garbage collections
So is there any way that I can remove all the detached-element while leaving the certain page or why don't browser removed this from memory
I cant offer any more accurate assumption or suggestion if what we have is I use javascript information. Countless consequences from countless combination of libraries, stacks and techniques make this impossible to guess.

Memory Management in AngularJS

I am new to angular, so maybe I'm going about this completely wrong. I am attempting to make a treeView with angularJS directives. The code that I have so far accomplishes this, except that there appears to be a memory leak as each time the tree view reloads it slows down, and eventually crashes the browser.
I have created the following two directives to accomplish my task jscTreeView and jscTreeNode
This fiddler has my source, it builds you a random tree, and gives you the ability to choose the amount of nodes in the tree. If you bump that number up to a higher number, and reload several times you will notice that it progressively slows down to each time.
Any ideas on how to clean up after myself would be greatly appreciated, thanks.
Edit:
This fiddler is a second attempt with this one I went in a completely different direction. It is much more efficient, and the code is more clean in my opinion. However, this one has an issue too. periodically, and seemingly randomly on refresh of the tree this one throws an infinite digest exception.
Note: not all of the functionality that was in the former tree is in the current tree yet. That is just because I have not programmed it yet.
As the discussion in the comments indicates, I was creating, but never properly releasing, scopes in my tree view. While the solution was not very easy to figure out it is actually quite an easy solution, and clarified things a lot for me.
What I needed to do was make a clone of the root scope of my tree var newScope = scope.$new();, I then built all of the rest of the subtrees as well as their associated nodes and compiled with the cloned scope newScope. After the compile it stores the cloned scope into a variable private to the directive lastScope = newScope;. When the watch property is updated, and calls back to my directive the last cloned scope is destroyed lastScope.$destroy();. Destroying that cloned scope automatically destroys any child scope created beneath it (the nodes, as well as the subtrees). A new clone of the scope is created, and the process is repeated, thanks to #Jorg's tool to count scopes, I can see that everything is being cleaned up nicely on each iteration. Here is a fiddle to the solution.

angularjs memory consumption issue

Recently I had the opportunity of building a new web application, and thought of trying out Angular to get a good understanding of it. So yeah, I'm fairly new to this framework.
After understanding the nuances of the framework, I found it surprisingly easy to work with. Everything about my experience had been just great, until users started reporting the utterly laggy performance of the application.
The application is fairly simple—it's got 2 screens. One which shows a list of deals, and another where users can add/edit deal information—this second page is a simple form expecting the user to enter deal related information. It looks like this:
The outlined sections are rendered using ng-repeat. The retailers list has some 530 entries whereas the brand list has about 400 entries.
After a bit of profiling, I figured out that visiting this second form screen would keep on increasing the memory consumption of the browser. The first screen doesn't have any such effect. I simply toggled between the first screen and this second form screen, and found that every time this screen would get loaded, the memory consumption would spike by 50-75 MB. Eventually, the browser would just freeze up. Here's how the memory profile looks:
As you can see, the consumption keeps going up, and there's no sign of any GC! Every spike in the node count and memory trace correspond to a visit to the second form-based screen.
Now I have already checked out a whole lot of issues around angular and memory consumption, but each of them mentions that the $scope for any of the views will get removed when a new view loads. The DOM node count certainly doesn't indicate such a thing for me :/
I also came across 2 important points related to the usage of ng-repeat:
Avoid invocation of any function within the ng-repeat directive.
Don't have a two-way binding using ng-model within a ng-repeat directive.
Both of these I've avoided in the second screen, and yet, the memory consumption is going through the roof.
My question might seem to be yet another memory related question w.r.t angular, but I've really tried to get some sort of closure on this and haven't found one.
Would really appreciate any assistance on this, as my decision to progress with the usage of angular for the rest of the portal hinges on solving this issue.
Thanks for reading!
Update 1
Based on Ilan's suggestion, let me add that I make use of 2 plugins for rendering the dropdown and the implementing the date-picker.
For the dropdown, i'm using Bootstrap-select and for the date-picker, I'm using Bootstrap-datepicker.
For bootstrap-select to work, I had to write a custom directive which fired a broadcast on the $last event of ng-repeat. It looks something like this:
.directive('onFinishRender', function($timeout) {
return {
restrict : 'A',
link : function(scope, element, attr) {
if (scope.$last === true) {
$timeout(function() {
scope.$emit('ngRepeatFinished');
});
}
}
};
});
Then in the controller, I rely on this event to invoke the render for the dropdown plugin:
$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
$('#retailer').selectpicker('render');
});
For the bootstrap-datepicker, I do not have to do such an elaborate thing, as I only need to wrap the date input field using JS.
Update 2
After turning off the plugins, the memory consumption reduces drastically. However, the problem of a leak still persists. Earlier, whenever the form view was getting loaded, the memory would spike by 50-60 MB. After turning off the plugins, it spikes by 25-35 MB. But as you can see below, the memory consumption keeps on piling up.
I recently spent nights and days finding similar memory leaks as that of yours. These is no direct answer to your question. You will have to do the research but i can give you some pointers to finding the leak.
Don't use any other plugin in your chrome browser except for developer toolbar when debugging leak.
Timeline is good to figure out that there is a leak but to actually see the leak, use profiler tab. It runs a GC everytime you take a Heap Snapshot and gives you a clue if you improved or not.
If you are seeing memory leak in MBs than it is coming from DOMElements. With the size of leaks that you mentioned, i can tell that your whole document is hanging as detached dom element because of one or two components in your page are not getting released and are still hanging as attached dom.
Remove all the elements from your second page and do the switch to see if memory is increasing. If it does, first page has the leak otherwise do the same with second page.
Once you have located which page has the leak, remove all component from that page and add them one by one to see when leak returns.
Hope these steps help you in some way. Also i have found that using $timeout in directive can cause leaks just in case it helps.

how can I exclude an element from an Angular scope?

my premise was wrong. while AngularJS was certainly slowing things down, it was not due to the problem I describe below. however, it was flim's answer to my question - how to exclude an element from an Angular scope - that was able to prove this.
I'm building a site that generates graphs using d3+Raphael from AJAX-fetched data. this results in a LOT of SVG or VML elements in the DOM, depending on what type of chart the user chooses to render (pie has few, line and stacked bar have many, for example).
I'm running into a problem where entering text into text fields controlled by AngularJS brings Firefox to a crawl. I type a few characters, then wait 2-3 seconds for them to suddenly appear, then type a few more, etc. (Chrome seems to handle this a bit better.)
when there is no graph on the page (the user has not provided enough data for one to be generated), editing the contents of these text fields is fine. I assume AngularJS is having trouble when it tries to update the DOM and there's hundreds SVG or VML elements it has to look through.
the graph, however, contains nothing that AngularJS need worry itself with. (there are, however, UI elements both before and after the graph that it DOES need to pay attention to.)
I can think of two solutions:
put the graph's DIV outside the AngularJS controller, and use CSS to position it where it's actually wanted
tell AngularJS - somehow - to nevermind the graph's DIV; to skip it over when keeping the view and model in-sync
the second option seems preferable to me, since it keeps the document layout sane/semantic. is there any way to do this? (or some, even-better solution I have not thought of?)
Have you tried ng-non-bindable? http://docs.angularjs.org/api/ng.directive:ngNonBindable
<ANY ng-non-bindable>
...
</ANY>

Resources