GXT HandlerManager Bus Memory Leak - javascript

I'm search for a memory leak in a GWT application. I started with Chrome to create heap dumps and to compare them after certain actions.
In the summary of each heap dump I can see that after big amounts of arrays, Maps, HashMaps one of the biggest groups of classes is the HandlerManager.Bus class. Each HandlerManager.Bus item contains some Maps. Every click they accumulate in the heap and they don't get removed by the GC.
Starting GC manually also does not help.
Further reading shows that HandlerManager has got to do with ClickEvents and MouseEvents. I'm now looking for those events and source code where these are connected to fields of views and grids and other gwt/gxt code.
Please give a some hints what typically can go wrong with these classes.
I assume that there is some static classes and never lose the reference to this events and so the GC cannot remove them.
It is too bad that I cannot follow the memory objects in the heap as easy like I can do in MAT.
Thanks for your suggestions.

I've definitely seen that problem before. You'll notice that all of the calls that add handlers return a HandlerRegistration. Save these in a list. When you are done with a class that contains a list of handlers, go through the list and remove each handler. It's been a while since I've seen any GWT/GXT but I think it goes something like this.
List<HandlerRegistration> handlerList = new LinkedList<>();
public void addListeners() {
handlerList.add(myComboBox.addListener(mySelectionHandler));
}
public void onClose() {
handlerList.forEach(handler -> handler.removeHandler());
}

Related

How to "follow" the references / memory profile of specific Javascript values, or how to tie references in memory profiler to source code

I'd like to know if it's possible (with any browser / dev tools) to pick a specific value or closure variable while debugging and "follow" or "watch" it somehow into future execution points on the page. Basically, a memory profiler attached to just a single value, which would show during debugging or snapshots whether that value is still being retained either directly or indirectly. Alternatively, I'd like to know if it's possible to look at references in the memory profiler/snapshot view in, say, Chrome, and tie those references to actual points in the source code.
My problem is that I am debugging a memory leak caused by rebuilding a DOM tree for a portion of a fairly complex page. Even taking a very controlled memory snapshot that just looks at a single redraw (removing the old DOM tree and adding a new one, where I know that I'm unintentionally retaining a reference to a small part of the old one), there are still hundreds of objects to look through, and to be quite honest I find the memory profiler in Chrome to be very confusing to navigate through. And even when I find references that might be of interest, I'm at a loss as to how to tie them to points in the code - it's great to know that I'm retaining an HTMLDivElement somewhere but that could be almost any of the files...
So basically, I'm unsure how to proceed, and the two solutions I'm asking about are the only things I can think of, if there is any way to do them. Sorry that this is such a vague question, I am open to other ways of tackling this as well.

Finding JavaScript memory leaks with Chrome

I've created a very simple test case that creates a Backbone view, attaches a handler to an event, and instantiates a user-defined class. I believe that by clicking the "Remove" button in this sample, everything will be cleaned up and there should be no memory leaks.
A jsfiddle for the code is here: http://jsfiddle.net/4QhR2/
// scope everything to a function
function main() {
function MyWrapper() {
this.element = null;
}
MyWrapper.prototype.set = function(elem) {
this.element = elem;
}
MyWrapper.prototype.get = function() {
return this.element;
}
var MyView = Backbone.View.extend({
tagName : "div",
id : "view",
events : {
"click #button" : "onButton",
},
initialize : function(options) {
// done for demo purposes only, should be using templates
this.html_text = "<input type='text' id='textbox' /><button id='button'>Remove</button>";
this.listenTo(this,"all",function(){console.log("Event: "+arguments[0]);});
},
render : function() {
this.$el.html(this.html_text);
this.wrapper = new MyWrapper();
this.wrapper.set(this.$("#textbox"));
this.wrapper.get().val("placeholder");
return this;
},
onButton : function() {
// assume this gets .remove() called on subviews (if they existed)
this.trigger("cleanup");
this.remove();
}
});
var view = new MyView();
$("#content").append(view.render().el);
}
main();
However, I am unclear how to use Google Chrome's profiler to verify that this is, in fact, the case. There are a gazillion things that show up on the heap profiler snapshot, and I have no idea how to decode what's good/bad. The tutorials I've seen on it so far either just tell me to "use the snapshot profiler" or give me a hugely detailed manifesto on how the entire profiler works. Is it possible to just use the profiler as a tool, or do I really have to understand how the whole thing was engineered?
EDIT: Tutorials like these:
Gmail memory leak fixing
Using DevTools
Are representative of some of the stronger material out there, from what I've seen. However, beyond introducing the concept of the 3 Snapshot Technique, I find they offer very little in terms of practical knowledge (for a beginner like me). The 'Using DevTools' tutorial doesn't work through a real example, so its vague and general conceptual description of things aren't overly helpful. As for the 'Gmail' example:
So you found a leak. Now what?
Examine the retaining path of leaked objects in the lower half of the Profiles panel
If the allocation site cannot be easily inferred (i.e. event listeners):
Instrument the constructor of the retaining object via the JS console to save the stack trace for allocations
Using Closure? Enable the appropriate existing flag (i.e. goog.events.Listener.ENABLE_MONITORING) to set the creationStack property during construction
I find myself more confused after reading that, not less. And, again, it's just telling me to do things, not how to do them. From my perspective, all of the information out there is either too vague or would only make sense to someone who already understood the process.
Some of these more specific issues have been raised in #Jonathan Naguin's answer below.
A good workflow to find memory leaks is the three snapshot technique, first used by Loreena Lee and the Gmail team to solve some of their memory problems. The steps are, in general:
Take a heap snapshot.
Do stuff.
Take another heap snapshot.
Repeat the same stuff.
Take another heap snapshot.
Filter objects allocated between Snapshots 1 and 2 in Snapshot 3's "Summary" view.
For your example, I have adapted the code to show this process (you can find it here) delaying the creation of the Backbone View until the click event of the Start button. Now:
Run the HTML (saved locally of using this address) and take a snapshot.
Click Start to create the view.
Take another snapshot.
Click remove.
Take another snapshot.
Filter objects allocated between Snapshots 1 and 2 in Snapshot 3's "Summary" view.
Now you are ready to find memory leaks!
You will notice nodes of a few different colors. Red nodes do not have direct references from Javascript to them, but are alive because they are part of a detached DOM tree. There may be a node in the tree referenced from Javascript (maybe as a closure or variable) but is coincidentally preventing the entire DOM tree from being garbage collected.
Yellow nodes however do have direct references from Javascript. Look for yellow nodes in the same detached DOM tree to locate references from your Javascript. There should be a chain of properties leading from the DOM window to the element.
In your particular you can see a HTML Div element marked as red. If you expand the element you will see that is referenced by a "cache" function.
Select the row and in your console type $0, you will see the actual function and location:
>$0
function cache( key, value ) {
// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
if ( keys.push( key += " " ) > Expr.cacheLength ) {
// Only keep the most recent entries
delete cache[ keys.shift() ];
}
return (cache[ key ] = value);
} jquery-2.0.2.js:1166
This is where your element is being referenced. Unfortunally there is not much you can do, it is a internal mechanism from jQuery. But, just for testing purpose, go the function and change the method to:
function cache( key, value ) {
return value;
}
Now if you repeat the process you will not see any red node :)
Documentation:
Eliminating memory leaks in Gmail.
Easing JavaScript Memory Profiling In Chrome DevTools.
Here's a tip on memory profiling of a jsfiddle: Use the following URL to isolate your jsfiddle result, it removes all of the jsfiddle framework and loads only your result.
http://jsfiddle.net/4QhR2/show/
I was never able to figure out how to use the Timeline and Profiler to track down memory leaks, until I read the following documentation. After reading the section entitled 'Object allocation tracker' I was able to use the 'Record Heap Allocations' tool, and track some some Detached DOM nodes.
I fixed the problem by switching from jQuery event binding, to using Backbone event delegation. It's my understanding that newer versions of Backbone will automatically unbind the events for you if you call View.remove(). Execute some of the demos yourself, they are set up with memory leaks for you to identify. Feel free to ask questions here if you still don't get it after studying this documentation.
https://developers.google.com/chrome-developer-tools/docs/javascript-memory-profiling
Basically you need to look at the number of objects inside your heap snapshot. If the number of objects increases between two snapshots and you've disposed of objects then you have a memory leak. My advice is to look for event handlers in your code which do not get detached.
There is an introduction video from Google, which will be very helpful to find JavaScript memory leaks.
https://www.youtube.com/watch?v=L3ugr9BJqIs
You also might want to read :
http://addyosmani.com/blog/taming-the-unicorn-easing-javascript-memory-profiling-in-devtools/
It explains the use of the chrome developer tools and gives some step-by-step advices on how to confirm and locate a memory leak using heap snapshot comparison and the different hep snapshot views available.
You could also look at the Timeline tab in developer tools. Record the usage of your app and keep an eye on the DOM Node and Event listener count.
If the memory graph would indeed indicate a memory leak, then you can use the profiler to figure out what is leaking.
A couple of important notes in regards to identifying memory leaks using Chrome Developer tools:
1) Chrome itself has memory leaks for certain elements such as password and number fields. https://bugs.chromium.org/p/chromium/issues/detail?id=967438. Avoid using those while debugging as they polute your heap snapshot when searching for detached elements.
2) Avoid logging anything to the browser console. Chrome will not garbage collect objects written to the console, hence affecting your result. You can suppress output by placing the following code in the beginning of you script/page:
console.log = function() {};
console.warn = console.log;
console.error = console.log;
3) Use heap snapshots and search for "detach" to identify detached DOM elements. By hovering objects, you get access to all the properties including id and outerHTML which may help identify each element.
If the detached elements are still too generic to recognize, assign them unique IDs using the browser console prior to running your test, e.g.:
var divs = document.querySelectorAll("div");
for (var i = 0 ; i < divs.length ; i++)
{
divs[i].id = divs[i].id || "AutoId_" + i;
}
divs = null; // Free memory
Now, when you identify a detached element with, lets say id="AutoId_49", reload your page, execute the snippet above again, and find the element with id="AutoId_49" using the DOM inspector or document.querySelector(..). Naturally this only works if your page content is predictable.
How I run my tests to identify memory leaks
1) Load page (with console output suppressed!)
2) Do stuff on page that could result in memory leaks
3) Use Developer Tools to take a heap snapshot and search for "detach"
4) Hover elements to identify them from their id or outerHTML properties
I second the advice to take a heap snapshot, they're excellent for detecting memory leaks, chrome does an excellent job of snapshotting.
In my research project for my degree I was building an interactive web application that had to generate a lot of data built up in 'layers', many of these layers would be 'deleted' in the UI but for some reason the memory wasn't being deallocated, using the snapshot tool I was able to determine that JQuery had been keeping a reference on the object (the source was when I was trying to trigger a .load() event which kept the reference despite going out of scope). Having this information at hand single-handedly saved my project, it's a highly useful tool when you're using other people's libraries and you have this issue of lingering references stopping the GC from doing its job.
EDIT:
It's also useful to plan ahead what actions you're going to perform to minimize time spent snapshotting, hypothesize what could be causing the problem and test each scenario out, making snapshots before and after.
Adding my 2 cents here with the tools available in 2021: https://yonatankra.com/how-to-profile-javascript-performance-in-the-browser/
There's a short video version here: https://yonatankra.com/detect-memory-leak-with-chrome-dev-tools

How does v8 call DOM's function?

I am studying v8 sources.
I have spent 3 weeks but I couldn't find that how 8v call DOM's function.
Example for,
<script>
document.writeln("Hello V8");
</script>
I want to know process of call sequences, writeln() function of DOM.
Could you explain about this or give me some hints.
You could check V8HTMLDocumentCustom.cpp file where the .writeln function is found:
void V8HTMLDocument::writelnMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args){
HTMLDocument* htmlDocument = V8HTMLDocument::toNative(args.Holder());
htmlDocument->writeln(writeHelperGetString(args), activeDOMWindow()->document());
}
As you can see there are several headers included, some of those includes lead you to other headers, where you find files like V8DOMConfiguration.h
V8DOMConfiguration.h has some comments:
class V8DOMConfiguration {
public:
// The following Batch structs and methods are used for setting multiple
// properties on an ObjectTemplate, used from the generated bindings
// initialization (ConfigureXXXTemplate). This greatly reduces the binary
// size by moving from code driven setup to data table driven setup.
What I get from this is that Chrome V8 creates "Wrapper Worlds" with objects, recreating DOMs for each one of them, then it just pass data to the active window created, though.
I'm not well versed in V8, however this is a starting point. Maybe someone with a deeper knowledge of it can explain it better.
Update
As #Esailija points out V8 engine when run without a browser has no DOM available. As DOM is part of Webkit/Blink, linked references point to them. Once browser has rendered DOM then V8 Objects are matched with DOM tree elements. There's a related question about this here: V8 Access to DOM

PhoneGap Memory Management

For few months now I have been developing an Android app using PhoneGap 2.8 and on the javascript side I have used Backbone and jQuery as my main frameworks. As my application has grown to a reasonable size, I have started to notice a considerable memory consumption. Having read different articles that explain why PhoneGap requires considerable amount of memory even to run, I still believe that I can do some optimization to how i use memory.
In BackBone we have a Router object that maps URI-s to specific functions, which render me something called a View object. Not only I implemented my router functions to create a view and render it, but I also store globally reference to currently being displayed view. So before a new view is created, I tell the old view to make some clean up (That is done recursively since views can contain more "sub" views). Under clean up I currently tell view to undelegate his events (I trust Backbone removes the event listeners). Not much more is done currently. Once new view is rendered, global variable will reference the new view. I trust that javascript GC will release the memory, used by the old view. Alas, I dont things this is happening- the more I navigate around my app, the more memory is being used up. I am aware that there is some memory leaking going on, but I can't figure out what is it, that takes memory. One thing I suspect is that old objects are not being garbage collected properly for some reason. I suspect that once I render new html (DOM) over some container, perhaps old DOM is causing memory leaks, perhaps some event handlers are being unnecessarily stored somewhere.
What I would like to know, if there is any tools or commands or tips on how can I debug/ trace/ measure where memory is being allocated. Is there a way to access all event listeners and measure them somehow (same for DOM). Any article to smart memory efficient techniques would also be appreciated. Currently only thing that I can thing of to do, is to start recursively deleting all attributes of the objects (in the end objects as well) I am willing to destroy.
Any suggestion is very welcome!
Thank you in advance.
I faced similar issues with my first phonegap app. Few techniques we managed to apply were
*old view - view getting navigated away
Unbind all events associated with old view
Remove all nodes attached to the view from dom, to make sure event are also removed
Remove old view object, model/collection, so that there are no instances remaining on the DOM
Moreover try to use prototyping as much as possible, as functions created via prototype occupy space in RAM only once. So if the view is created/initiated again, its associated/child functions aren't going to be pushed into RAM again
Most imp, make sure 'this' pointer isn't leaking anywhere between files. One of my workplace used to get stuck after 1.5 hrs of play and after a week debugging, we came to find out that there was a leakage of this pointed between 2 files/objects/views, which created a circular referencing and make the DOM to explode.
Also you can try to use Google Chrome's profiling tool
Few useful links
http://blog.socialcast.com/javascript-memory-management/
Backbone.js Memory Management, Rising DOM Node Count

Identify javascript closures with developer tools

I am currently developing a website that is pure javascript and relies heavily on the jQuery & jQuery UI libraries (this site is not intended for use by a general public, hence progressive enhancement is not a strict requirement for this project). I am encountering a significant memory leak on executing the following code:
oDialogBox = $("<div>...</div>");
/* Add useful things to the dialog box here */
oDialogBox.appendTo("body");
oDialogBox.dialog({
/* Other dialog box settings here */
close: function(event, ui) {
oDialogBox.dialog("destroy");
oDialogBox.remove();
oDialogBox = null;
}
});
At any given time in this dialog box, I am creating, removing and modifying a large number of instances of jQuery UI buttons, multiselects (per the Multiselect widget created by Eric Hynds) and on click event handlers. According to jQuery UI documentation, calling .remove() on oDialogBox should result in all child widgets being unbound and deleted. Yet my detached DOM tree shows a significant number of garbage elements that the GC isn't collecting.
It is highly likely I have missed a large set of closures that need to be finished off safely. How do I do the following:
1) How do I identify which closures are keeping a given detached DOM object alive (either in Firefox or Chrome)?
2) Assuming the complete set of closures is identified, does anything beyond nulling the variable need to be done to assure marking the DOM element for garbage collection?
3) I have also noticed my list of arrays stored by the page is giant and contains references to DOM elements not being gathered by the GC. Is there a documented best practice for cleaning arrays from javascript and allowing all elements to be marked for deletion? (Note: this is a current prime suspect for the source of the memory leak)
I'm afraid that I don't have a great answer for #1. I haven't found any really good tools for this myself, even given how good the development tools have become over the last few years. The best advice I can give is to always keep things in the smallest scope you possibly can. If things don't escape, it's generally easier to simply figure out where the references must be.
As to #2, there can be further concerns. If the object referenced by variable v1 closes over the free variables of some function, removing v1 will not be enough to make them eligible for garbage collection if another variable v2 closes over v1 in some other function. So I guess if you really mean the "complete set of closures", then you should be all set. But this might get hairy. Again, if most object have references only in narrow scopes, these problems are much less severe.
For #3, what sorts of arrays are you discussing? If it's jQuery collections, then perhaps you simply have too many of them around. The only reason I know for them to stay around for a long time is to bind event handlers to them, and that is almost always better handled by event delegation on parent elements. If it's you're own custom arrays, do you really have a good reason to store references to them in arrays that last for any substantial length of time? I've rarely found one.

Categories

Resources