What is InternalNode in chrome heap profile - javascript

I am diagnosing a memory leak in a jQuery based single page application using the Chrome DevTools heap snapshot tool as described on https://developer.chrome.com/docs/devtools/memory-problems/#discover_detached_dom_tree_memory_leaks_with_heap_snapshots
I have solved some issues this way, but I have now hit a roadblock where I can no longer determine what is keeping an object in memory. For example, for one of the objects it returns the following retainers:
From what I can tell, the object is retained because it's used inside a closure scope of a click event.
But the click event is on a detached HtmlDivElement, which should be garbage collected.
It is somehow linked to the window object via InternalNode objects. I have searched all over the internet, but I'm unable to find what these InternalNode objects are.
My question is, what are these InternalNode objects and how I can "free" them so my objects are garbage collected.

TL;DR
Leak is caused by https://crbug.com/1177010
Clicking on an element outside the detached element prevents the memory leak from occuring.
Following #wOxxOm's comment, I have compiled a version of Chromium with the enable_additional_blink_object_names flag enabled so that it shows the names of the InternalNode objects.
It appears blink:MouseEventManager is preventing the detached dom element from being garbage collected.
This finally lead me to https://crbug.com/1177010, which I could confirm by clicking outside the detached element before taking another heap snapshot.

Related

How to find out what's causing my Javascript to crash the browser tab?

I'm making a rather extensive game using Javascript. It is a kind of online game maker that allows players to upload media files and use them to create worlds. Unfortunately, it is rather prone to crashing the browser tab at unpredictable moments. So far, I have found no pattern to this - sometimes it happens within a few minutes, other times it can run for hours without a problem.
I have tried enabling logging in Chrome, but the crashes don't seem to generate an error report in the chrome_debug file.
I thought it might be that the program was using too much memory (given the game's open-ended nature, some worlds can involve downloading rather large data files - though this seems unrelated to when the crash actually happens - while large worlds do seem to be more crash-prone, they do not always crash when the world's data is loaded).
I tried using Electron to turn it into an executable app, but the app still crashes. That shouldn't happen if it's a memory issue, right?
Is there any way of finding out what is causing the code to crash?
Most unpredictable crashes in Javascript are caused by memory leaks - objects that are still stored in memory and not being picked up by the garbage collector. Every object in Javascript is stored in a variable somewhere within the global scope, or is associated with another object that is itself connected to the global scope. When a "branch" of the "tree" is removed and can no longer be accessed by the global scope, the garbage collector destroys it.
However, if an object is not being removed from the global scope when it should be, it remains in memory. This usually happens when objects are added to an array but are not removed from that array when they are no longer in use. Over time, these objects build up until the process crashes due to memory overload.
To find memory leaks in Chrome, press F12 and open the Performance tab. By recording the page over time, you can view the amount of memory being used. The green line (nodes) is the most important here - it refers to the number of objects in memory. If nodes are constantly increasing over time (there will always be increases and decreases, but if the overall level is constantly rising) this generally means there's a memory leak.
To find which specific objects are causing the problem, open the Memory tab to take snapshots or timeline profiles of the memory heap. This gives you a count of the specific objects that are in memory at any given time. If there are more of some kind of object than there should be, that's where the leak is.

Can I get the GC'd memory from dev tools?

I have a large app thata I am debugging. I have noticed a saw-tooth memory pattern that indicates that there is frequent GC going on.
In an effort to debug this I am trying to find the contents of the memory that is being GC'd. Is this possible in chrome with dev tools? I know I can take heap snapshots, but how do I guarantee that this happens immediately before and after a GC? I know I can trigger a heap snapshot from code, but same question.
Insight into the garbage collection is not available yet in the DevTools. I have requested this feature some time ago though. You can "star it" to indicate that you would also like to have it.
As for the snapshots, you won't be able to use them for your purpose. Before each snapshot is made all garbage is collected.
Are "dead" (unreachable) objects included in snapshots?
No. Only reachable objects are included in snapshots. Also, taking a snapshot always starts with doing a GC.
source
Your best shot is to record heap allocations ("Profiles" > "Record Heap Allocations") and use memory snapshots to understand what objects are being created by the app. With that knowledge, you can try identifying shortly lived objects (that cause the sawtooth pattern).
BTW, if you are using requestAnimationFrame, you should know that it's causing saw tooth pattern by itself.
With Record Heap Allocation profile type you can get the information about allocated objects.
You need to enable "Record heap allocation stack traces" option in the DevTools settings.
See screenshot.
After that you need to record "Record heap allocations" snapshot type.
The recording process may significantly slow down the page because DevTools scans the js stack each time when the page allocates an object. As a result you will get the snapshot which has the information about allocations. In many cases DevTools can detect the class name of the objects. See screenshot.
In the snapshot you need to select Allocation view.
I think the information in the grid could help you to solve your problem.
In the screenshot you can see that there were 41k allocations for a class but only 12k of them still alive. So 29k objects were the garbage. And even if you don't see the name of the object you could jump into sources where the objects were allocated.

Using Chrome's heap snapshot analyzer, how do I interpret dead-ends in the retainers view

I have a single-page app that is leaking fairly substantially. I am trying to track down the memory leaks using Chrome's built-in memory profiling tools. The heap snapshot has been giving me a lot of success in tracking down quite a few problematic code blocks, but I have now reached a bit of a dead-end.
I have taken a heap snapshot and isolated a variable that has clearly leaked. I then open it up the retainers view so that I can see why the object has not been garbage collected. What I am now seeing in the retainers view (see below) is confusing me. It keeps reaching a dead-end even though it claims that the given node in the graph still has a distance of 11. I'm not sure why it won't let me dig into the object when it says that there is still depth there. I was expecting that I would be able to expand all the way to a global variable on the window object.

JQuery Remove and memory leaks

Im working on a game, and ive seen a lot of memory consuption, im using jquery animate, and after the animation is done, i .remove() the element, my question is, after removing an element from the dom tree, the object still exist in memory?
Javascript is a garbage collected language. That means that an object in memory will be released when no code holds any references to it and (for a DOM object) it's not in the DOM. So, when you remove an object from the DOM, as long as no other part of your javascript has a reference to that DOM object, the DOM object will be cleaned up and it's memory returned to the available memory pool when the garbage collector gets a chance to run.
Keep in mind that when memory is freed by the garbage collector, it may not be returned to the system right away or ever. It may stay as memory allocated to the browser, but it will be available for use by other memory requests within the browser. So, freeing memory in your script won't necessarily make the total memory used by the browser go down.
It is only a memory leak if repeatedly carrying out the same operation over and over causes the total memory used by the browser to continually rise. Only then can you be sure that some memory is being permanently consumed by a "leak".
There are a number of nuances about garbage collection, particularly for older versions of IE, but for modern browsers, mostly what you need to keep in mind is that if you hold a reference to an object in your own javascript data structures, it will not be garbage collected. If you don't hold a reference to it and it's not in the DOM, it will be freed and its memory recycled.
If there are no references to the element, garbage collection will clean it up on its next run. You're just fine using .remove, but don't bother worrying about the garbage collection.

Do I have to clean custom properties (Expandos) on window.onunload event?

In one article I have seen that it may be good to clear all expandos on window.unload event to prevent memory leaks.
I cannot understand why to do this.
Isn't the browser cleaning all the DOM and its relevant resources of it once you leave the page anyway?
Thanks,
burak ozdogan
Hey, great question. The problem is with circular references between JavaScript objects and DOM nodes.
Let's say you have a global JavaScript object which points to a DOM node and the node has an expando property back to the object. When the page unloads, the script engine "nulls-out" the JavaScript object so it no longer points to the DOM node. But, it cannot release the object from memory because there is still a reference to it (from the DOM). Then the script engine terminates.
Expando properties on the DOM are nothing but references to other objects. When the DOM is being cleaned up, it breaks those references but assumes that the objects are still being used. In this example, the DOM waits for the script engine to clean up the objects that belong to it, but the script engine has already terminated.
So, the problem is that the DOM only takes care of the memory that belongs to it and assumes the script engine will do the same.
I hope this helped.
See: http://msdn.microsoft.com/en-us/library/bb250448%28VS.85%29.aspx

Categories

Resources