ArrayBuffer memory leak and Firefox memory tool - javascript

I'm trying to debug a memory leak through the usage of Firefox memory tool.
What I was able to find is that an ArrayBuffer object keeps increasing its size second after second. This object is used to receive audio/video data. If not managed, this behaviour results into a out of memory condition in which the computer literally freezes. The feeling is that the object is not properly released or cleared.
Through the memory tool, however, is not possible to go back to the exact variable that is causing the issue. I've checked also with the "Record call stacks" option and grouping by call stacks, but unfortunately - exactly in corrispondence of the aforementioned element - the tool says "(no stack available)".
Does anyone know how would it be possible to retrieve additional information?
Thanks

Related

Tool or technique to discover which JS/jQuery script is freezing the page

Which tool is used to discover what JS/jQuery is consuming too many resources or in infinite loop?
More specifically I have an issue with this template: http://pages.revox.io/dashboard/latest/html/
Opening that page on Firefox 46.0.1 freezes the page after a few minutes. I'm unable to discover which JS/jQuery is causing this freeze with Firebug since it seems to be a script that is simply consuming too many resources and not in a plain freezing never ending loop (which would trigger the "Script XYZ is taking too long to execute" message)
Firefox 46.0 for Ubuntu appears to have a pretty good debugger built into it.
Using the system monitor it's easy to see your page requires a fair amount of memory.
It's fairly easy to produce a call graph in Firefox if you go to Tools->Web Developer->Performance and record your page for a little while.
Once you've stopped the recording, just select the data in the menu on the left and Call-Tree on the top of the debug frame.
It presents a breakdown of which functions use the most processor time.
Looks to me like whatever the Gecko function is, it is just really expensive.
Also, the console points out some interesting things:
mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create d3.v3.js:3:157
Use of getPreventDefault() is deprecated. Use defaultPrevented instead. html
Empty string passed to getElementById().
Maybe addressing the issues pointed out by the console will help your freezing issue.

JavaScript WebSocket Idle time in DevTools timeline

I have an application that does the following:
WebSocket.onmessage
put bytes into a queue (Array)
on requestAnimationFrame
flush queue, rendering the received bytes using canvas/webgl
The application receives and plots realtime data. It has a bit of jerk/jank and while profiling my rendering code, I noticed that while the actual rendering seems execute quickly, there are large chunks of idle time during the WebSocket.onmessage handler.
I tried shrinking the window, mentioned in Nat Duca's post, to check if I am "GPU bound". But, even with a small window, the timeline gives pretty much the same results.
What I am suspecting now is Garbage Collection. The application reads data from the WebSocket, plots it, then discards it. So to me, it seems unsurprising that I have a saw-tooth memory profile:
So my question is now two-fold:
1) In the browser, is it even possible to avoid this memory footprint? In other languages, I know I'd be able have a buffer that was allocated once and read from the socket straight into it. But with the WebSocket interface, this doesn't seem possible; I'm getting a newly allocated buffer of bytes that I use briefly and then no longer need.
Update:--- Per pherris' suggestion, I removed the WebSocket from the equation, and while I see improvement, the issue still seems to persist. See the screenshots below:
2) Is this even my main issue? Are there other things in an application like this that I can do to avoid this blocking/idle time?

How to find non-destroyed but GC'ed Javascript objects in Chrome?

I have an application with some objects (of type BaseTexture) on which an explicit destroy function should be called when they aren't of any more use. Otherwise they might leak some memory. This should be done before they are garbage collected (and obviously only can be done then), but it doesn't always happen.
In Java I would detect and log this using finalize, but such a thing does not exist in Javascript.
Can I detect this in Chrome (or in another browser)? I don't really care if it's buggy, requires flags, can only log a simple message, etc, as long as it works during development. The fact that a BaseTexture has been destroyed can be retrieved from its source property.
If the purpose of this is to check for memory leaks, then why cant you just run a chrome profile instead?
The Object allocation tracker can be used to find memory leaks at runtime, also the heap profiler can analyze memory graphs and compare snapshots to discover what objects are not being cleaned up by the gc.
Also the timeline memory view can help identify if you are forcing garbage collection too often by allocating too often (if thats of interest)
For more info, see:
https://developer.chrome.com/devtools/docs/javascript-memory-profiling
Also not sure if its helpful, but if you want to look at memory stats then you can enable memory info in chrome by running with the --enable-memory-info param, then you have access to window vars:
window.performance.memory.jsHeapSizeLimit
window.performance.memory.totalJSHeapSize
window.performance.memory.usedJSHeapSize

Chrome Rapid Memory Leak. How To Debug When Running Javascript Profiler Fixes Leak?

I'm making a game using canvas, and am running into strange Chrome behavior that I can't pin down. Sometimes when I load the game, the Chrome Task Manager will report that it's allocating +300MB a second, ramping up to over a few GB of memory in just a matter of 10 seconds or so, and it doesn't stop until the tab crashes.
When I try to run the javascript profiler, the problem stops. When I load the tab with the profiler running, it is perfectly stable. When the problem happens, and then I start the profiler, it will go from 1.5GB to a stable 40MB immediately. And the heap snapshot shows me what I would expect if the game was running stably.
My game is running on window.setInterval (I've tried requestAnimationFrame and recursive setTimeout and the problem still happens), and it happens more often with this is set high, meaning that when I set the game to 30FPS, this rarely ever happens, and when I set it to 60FPS, it happens over half the time. This is only happening on Chrome, Firefox seems fine.
How do I debug this, when Chrome seems to do garbage collection only when the profiler is running?
Also, I've noticed that some of my animations and keyboard inputs are a little funny when I push the FPS to 60. I assume that this could be related, but this is also the case in Firefox.
JavaScript is single-threaded which means all the work needs to be done on the same thread including queuing events (from setTimeout/rAF, keys etc.), rendering to canvas and so forth.
If the loop is very tight (time-budget-wise) there will simply not be any room for the browser to do other tasks such as GC - for Chrome this task seem to be secondary versus Firefox which gives this higher priority (likely to get more performance out of its engine). Basically the running code will block the browser from doing other things than executing the code itself.
A good indicator of this is when you lower the FPS leaving more space for event queue, clean-up etc. When the profiler is running it get more priority in order to catch all sort of things so for some reason GC gets to "sneak" in earlier when profiler is running (in lack of better term). But this is very browser specific and I do not know every underlying details here.
If the browser cannot purge events in the event queue it will eventually stack up and in worst case block/freeze/crash the browser.
In any case, it's hard to debug this (for pin-pointing reasons) as you won't, programmatically, have access to memory or CPU usage etc.
The closest thing is to use a high-resolution timer at the beginning and end of the code inside the loop to see if it comes close to the frame rate time.
For example:
function loop() {
var startTime = performance.now();
... other code ...
var innerLoopTime = performance.now() - startTime;
requestAnimationFrame(loop);
}
If your frame rate is 60 FPS then the time per frame would be 1000/60, or about 16.667ms.
If your innerLoopTime is very close to this time you will know that you need to optimize the code executed inside the loop, or lower the frame rate.
You could use the debugger to get time-cost per step inside the function but the debugger itself will add an overhead to the total. So do measuring the time, but the cost is lower.. it will be a matter of compromise no matter how one twist and turn this one.
I've found that a huge source of memory leaking in javascript code is usually closures.
If you're accessing a variable inside your setInterval that was declared outside, then you're most likely leaking some memory. As to whether or not this is the actual root cause of the issue is another question.
If you want to understand closures more and how they affect the performance of your js in action, look at this article by IBM on the topic. It gives good examples and ways to avoid memory leaks using them, as well as a few other possible sources of memory leaks.
We've noticed chrome + canvas is not as performant as firefox + canvas. As to GC occurring when you open chrome dev tools, well I'd guess you may have some code that nudges chrome in just the right way to do a GC. Do you have some sort of window resize handler? There might be something else that is doing something similar.
When in doubt bisect the code till it doesn't happen anymore.

Can I trigger JavaScript's garbage collection?

I want to trigger JavaScript garbage collection. Is it possible? Why would I want to, or not want to, do this?
I went out on a small journey to seek an answer to one of your questions: Is it possible?
People all over town are saying that deleting the references will do the trick. Some people say that wiping the object is an extra guarantee (example). So I wrote a script that will try every trick in the book, and I was astonished to see that in Chrome (22.0.1229.79) and IE (9.0.8112.16421), garbage collection doesn't even seem to work. Firefox (15.0.1) managed without any major drawbacks apart from one (see case 4f down below).
In pseudo-code, the test goes something like this.
Create a container, an array, that will hold objects of some sort. We'll call this container Bertil here on.
Each and every object therein, as an element in Bertil, shall have his own array-container declared as a property. This array will hold a whole lot of bytes. We'll call any one of Bertil's elements, the object, Joshua. Each Joshua's byte array will be called Smith.
Here's a mind map for you to lean back on:
Bertil [Array of objects] -> Joshua [Object] -> Smith [Array of bytes] -> Unnamed [Bytes].
When we've made a mess out of our available memory, hang around for a sec or two and then execute any one of the following "destruction algorithms":
4a. Throw a delete operand on the main object container, Bertil.
4b. Throw a delete operand on each and every object in that container, kill every Joshua alive.
4c. Throw a delete operand on each and every array of bytes, the Smiths.
4d. Assign NULL to every Joshua.
4e. Assign UNDEFINED to every Joshua.
4f. Manually delete each and every byte that any Joshua holds.
4g. Do all of the above in a working order.
So what happened? In case 4a and 4b, no browser's garbage collector (GC) kicked in. In case 4c to 4e, Firefox did kick in and displayed some proof of concept. Memory was reclaimed shortly within the minute. With current hardcoded default values on some of the variables used as test configuration, case 4f and 4e caused Chrome to hang, so I can't draw any conclusions there. You are free to do your own testing with your own variables, links will be posted soon. IE survived case 4f and 4e but his GC was dead as usual. Unexpectedly, Firefox survived but didn't pass 4f. Firefox survived and passed 4g.
In all of the cases when a browser's GC failed to kick in, waiting around for at least 10 minutes didn't solve the problem. And reloading the entire page caused the memory footprint to double.
My conclusion is that I must have made a horrible error in the code or the answer to your question is: No we can't trigger the GC. Whenever we try to do so we will be punished severely and we should stick our heads in the sand. Please I encourage you to go ahead, try these test cases on your own. Have a look in the code were comment on the details. Also, download the page and rewrite the script and see if you can trigger the GC in a more proper way. I sure failed and I can't for the life of me believe that Chrome and IE doesn't have a working garbage collector.
http://martinandersson.com/dev/gc_test/?case=1
http://martinandersson.com/dev/gc_test/?case=2
http://martinandersson.com/dev/gc_test/?case=3
http://martinandersson.com/dev/gc_test/?case=4
http://martinandersson.com/dev/gc_test/?case=5
http://martinandersson.com/dev/gc_test/?case=6
http://martinandersson.com/dev/gc_test/?case=7
You can trigger manually JavaScript garbage collector in IE and Opera, but it's not recommended, so better don't use it at all. I give commands more just for information purpose.
Internet Explorer:
window.CollectGarbage()
Opera 7+:
window.opera.collect()
Garbage collection runs automatically. How and when it runs and actually frees up unreferenced objects is entirely implementation specific.
If you want something to get freed, you just need to clear any references to it from your javascript. The garbage collector will then free it.
If you explain why you even think you need to do this or want to do this and show us the relevant code, we might be able to help explain what your alternatives are.
Check your code for global variables. There may be data coming through an ajax call that is stored, and then referenced somewhere and you did not take this into account.
As a solution, you should wrap huge data processing into an anonymous function call and use inside this call only local variables to prevent referencing the data in a global scope.
Or you can assign to null all used global variables.
Also check out this question. Take a look at the third example in the answer. Your huge data object may still be referenced by async call closure.
This answer suggests the following garbage collection request code for Gecko based browsers:
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
.garbageCollect();
Came across this question and decided to share with my recent findings.
I've looked to see a proper handling of a WeakMap in Chrome and it's actually looks okay:
1) var wm = new WeakMap()
2) var d = document.createElement('div')
3) wm.set(d, {})
at this stage weak map holds the entry cause d is still referencing the element
4) d = null
at this stage nothing references the element and it's weakly referenced object, and indeed after a couple of minutes entry disappeared and garbage collected.
when did the same but appended the element to the DOM, it was not reclaimed, which is correct, removed from the DOM and still waiting for it to be collected :)
Yes, you can trigger garbage collection by re-loading the page.
You might want to consider using a Factory Pattern to help re-use objects, which will greatly cut down on how many objects are created. Especially, if you are continuously creating objects that are the same.
If you need to read up on Factory Patterns then get yourself this book, "Pro Javascript Design Patterns" by Ross Harmes and Dustin Diaz and published by APress.
I was reading Trevor Prime's answer and it gave me a chuckle but then I realized he was on to something.
Reloading the page does 'garbage-collect'.
location.reload() or alternatives to refresh page.
JSON.parse/stringify and localStorage.getItem/setItem for persistence of needed data.
iframes as reloading pages for user experience.
All you need to do is run your code in an iframe and refresh the iframe page while saving useful information into localStorage. You'll have to make sure the iframe is on the same domain as main page to access its DOM.
You could do it without an iframe but user experience will no doubt suffer as the page will be visibly resetting.
If it is true that there is no way to trigger a GC, as implied by the other answers, then the solution would be for the appropriate browser standards group to add a new JavaScript function to window or document to do this. It is useful to allow the web page to trigger a GC at a time of its own choosing, so that animations and other high-priority operations (sound output?) will not be interrupted by a GC.
This might be another case of "we've always done it this way; don't rock the boat" syndrome.
ADDED:
MDN documents a function "Components.utils.schedulePreciseGC" that lets a page schedule a GC sometime in the future with a callback function that is called when the GC is complete. This may not exist in browsers other than Firefox; the documentation is unclear. This function might be usable prior to animations; it needs to be tested.

Categories