Firefox console.log preventing JavaScript String from getting garbage collected? - javascript

With the following code whenever console.log is enabled the String referenced by o.big will not get garbage collected. As soon as I remove the logging statement the memory for the big String gets freed after the execution of the handler function finishes.
I am using Firefox 9.0.1 and the memory profiling was done with about:memory.
$(function() {
var handler = function() {
var o = {};
o.big = (new Array(20*1024*1024)).join("x");
console.log(o.big);
delete o.big;
};
$("#btn").click(handler);
});
I am fairly new to JavaScript and it would be great if someone could point out to me why the String does not get marked by gc if used within console.log.

Although I'm not too familiar with Firefox's / Firebug's handling of console.log() I assume that the console showing the "logged" object provides a way of examining and interacting with it. This is at least the case for Chrome.
Therefore, the console needs a reference to the object which will be kept in memory and cannot be garbage collected until the console releases the reference (which may not happen until the page hosting the script is reloaded).
Finally, keep in mind that there is no explicit relationship between the delete operator and garbage collection.

Not sure if Firefox keeps a reference to the original string there. I'd argue that console.log() retains a copy, since strings are first-class members in JS.
You can see the string-chars memory usage dropping in about:memory, but heap-unclassified rising. This may be related to https://bugzilla.mozilla.org/show_bug.cgi?id=563700, or it may mean that FF's GC is broken.

Related

I am getting obscure memory leaks in my browser as I perform various ajax requests

After using the DevTools in Chrome and the equivalent tools in Firefox, I am having trouble finding out why a particular object is taking up lots of memory after it has gone out of scope and I would expect it to have been garbage collected.
In my case it turns out I was logging a large object to the console causing the object to remain in memory. Removing my console.log statement caused the object to be garbage collected as expected.

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

Does deleting variables before closing the tab/window help releasing memory?

I'm maintaining a JavaScript code where a function that does some heavy processing to generate arrays saves the results in a cache variable inside the function itself. It's implemented like this:
function heavyProcessingStuff(x) {
if(heavyProcessingStuff.cache == undefined)
heavyProcessingStuff.cache = [];
if(heavyProcessingStuff.cache[x] != undefined) {
return heavyProcessingStuff.cache[x]
} else {
return heavyProcessingStuff.cache[x] = x + 1
}
}
The weird thing is that there's a function executed when the page is unloaded that manually deletes every property of the cache variable, like this:
for (n in heavyProcessingStuff.cache) {
delete heavyProcessingStuff.cache[n]
}
I'm confused about why this was implemented this way.
Is this specific for some weird corner case? Is there any motivation to do so? Doesn't/shouldn't the browser garbage collect everything when the page closes?
Javascript uses garbage collection and it is best not to free memory explicitly. Good reading on this is in "De-referencing Misconceptions" in the article "Writing Fast, Memory-Efficient JavaScript".
A quote from the article:
It’s not possible to force garbage collection in JavaScript. You
wouldn’t want to do this, because the garbage collection process is
controlled by the runtime, and it generally knows best when things
should be cleaned up.
Without seeing the full context, there is one other possibility:
Earlier versions of IE (I know IE6 was susceptible), used a simple reference counting system for garbage collection. The trouble is that the DOM and JavaScript kept separate reference stacks.
This allowed for a situation to develop where the DOM (via an expando property) could hold onto a JavaScript reference -- and the JavaScript held onto a DOM reference.
This circular references would create a memory leak that lived on beyond the page, and the memory was only released when the page window was closed.
It was common to use the unload event to free memory and release any event handlers in an effort to avoid this.
In Chrome and Internet Explorer (or any browser that implements a process-per-tab model), you're right, there's absolutely no value. In fact, it's wasting CPU time to try and delete, since often when a tab is closed a process is killed, freeing up all non-shared resources.
For browsers that are a single process (Firefox still is, though progress is underway to change that), it's possible this could make the garbage collector do its work faster, if the reference counts get decremented to 0, but it's probably also pointless. Other than very old (IE6 for example) browsers, every modern garbage collector will probably sweep away everything on the next pass regardless of whether you explicitly remove references or not.

How do you clear memory in Javascript?

var Obj = function(){}; var X = new Obj();
will X = null properly clear memory?
Also would this be equivalent?
var Obj = function(){};
var X = {};
X.obj = new Obj();
delete(X.obj);
EDIT
It would seem that although deleting X.obj would NOT immediately clear memory, it would help the garbage collection. If I don't delete X.obj, there would still be a pointer to an object and so the GC may not clean it up.
Although I'm picking #delnan's answer, if you're reading this you should def also catch Benubird's article.
I also notice I accidentally wrote delete(X) originally instead of delete(X.obj) - sorry.
The short answer is that you don't. delete simply removes a reference (and not in the way you try to use it, see the above link - delete is one of those language features few people actually understand), nothing more. The implementation clears memory for you, but it's not your business when (and even if, strictly speaking - this is why one shouldn't rely on finalizers in GC'd languages that offer them) it does. Note though:
Only objects that can be proven to be unreachable (i.e. no way to access it) to all code can be removed. What keeps references to whom is usually fairly obvious, as least conceptually. You just need to watch out when dealing with lots of closures, as they may capture more variables than you think. Also note that circular references are cleaned up properly.
There's a bug in old (but sadly still used) IE versions involving garbage collection of JS event handlers and DOM elements. Google (perhaps even SO) should have better material on my memory.
On the plus side, that means you won't get dangling pointer bugs or (save of course the aforementioned pitfalls) memory leaks.
No, that will not clear memory.
Read this:
http://perfectionkills.com/understanding-delete/
No - Javascript runs GC when it feels like it.
The Delete method only deletes the reference - not the object. Any other references would be left out in the open waiting for the garbage collector.
JavaScript has its own GC, and it will run around and clean things up when nothing refers to them anymore.
I still think it's a good practice to null objects.
Deleteing an object also helps the GC because it will see something dangling, and say "I'm going to eat you because you're all alone (and now some cynical laugh)".
You should look at Deleting Objects in JavaScript
Even though there's a GC, you still want to ensure your script is optimized for performance as peoples computers, browsers, and fricken toolbars (and the number of them), will vary.
Generally speaking, memory management in Javascript is user-agent-specific. The basics of the garbage collector are through reference-counting. So, by setting a reference to null (using the delete keyword or by explicit assignment), you can assure yourself that a reference will be cleaned up, IF the object does not have any references that will live outside of its creation scope. That being the case, the GC will have already cleaned up any objects or variables whose scope has ended without your explicitly setting it to null.
There are some things to take care of, though - circular references are easy to create in JS, especially between a DOM element and an object. Care must be taken to clear (or not create in the first place) references to and/or from DOM elements within objects. If you do create a to/from reference related to DOM, be sure to explicitly clean them up by setting the references to null - both on your object and on the DOM element. Simply setting a parent object to null is not sufficient if there are child objects with references to/from DOM or localStorage because those references will live on, and if there was any reference from the child to the parent, then the parent will live on in memory because of that reference.
Web pages can actually leak trash in your memory this way - after you navigate away, the circular references keep objects and DOM elements in memory until you've restarted the browser!
An article on the subject: http://docstore.mik.ua/orelly/webprog/jscript/ch11_03.htm, and another detailed look: http://blogs.msdn.com/b/ericlippert/archive/2003/09/17/53038.aspx
JavaScript memory is generally handled similarly to Java - I mean there is (or there should be) a garbage collector which would delete the object if there is no references to it. So yes, simply "nullifying " the reference is the only way you should "handle" freeing memory, and the real freeing is the JS host part.

Memory leak in JavaScript (Chrome)

I'm calling a function 50 times a second, which does some expensive things as it is painting alot on a <canvas> element.
It works great, no problems there, but I just took a look at the memory usage and it was stealing 1MB a second of my RAM. Chrome seems to garbage collect, as it went down each minute or so, but then the usage grew again.
What I tried is putting return at certain places in my function so as to decide what part of my function exactly causes the leak. I've been able to cut it down to a specific line of code, after which the evil part comes, but I don't really know how to solve it.
My questions are:
What tool is available to effectively measure JavaScript memory leaks in Chrome?
Would it be effective to set variables to null / undefined after they have been used, something like disposing them?
If the source code is really necessary I wouldn't hestitate to post it here, but I must admit that it's both long and perhaps a little ununderstandable for others.
I'm just going to pull this quote directly, linked from the article;
Speaking of memory leaks, breaking circular references — the cause of the leaks — is usually done with simple null assignment. There’s usually no need to use delete. Moreover, null‘ing allows to “dereference” variables — what delete would normally not be able to do.
var el = document.getElementById('foo');
// circular reference is formed
el.onclick = function() { /* ... */ };
// circular reference is broken
el = null;
// can't `delete el` in this case, as `el` has DontDelete
For these reasons, it’s best to stick with null‘ing when breaking circular references.
delete Explained
Look at heap profile under the Profiles tab in Chrome's developer tools for information about memory usage.
You can do the following to prevent memory leaks:
Test your code with JSLint, to see if that will give you some pointers.
Use the var keyword to give your variables function scope, so they can be garbage collected when they go out of scope. Without the var keyword variables have global scope.
Use delete variable; statements to remove the object as well as the reference from memory. Setting the variable to null will only remove the object from memory, but not its reference.

Categories