I'm reading this article (http://javascript.info/tutorial/memory-leaks#memory-leak-size) about memory leaks which mentions this as a memory leak:
function f() {
var data = "Large piece of data";
function inner() {
return "Foo";
}
return inner;
}
JavaScript interpreter has no idea which variables may be required by
the inner function, so it keeps everything. In every outer
LexicalEnvironment. I hope, newer interpreters try to optimize it, but
not sure about their success.
The article suggests we need to manually set data = null before we return the inner function.
Does this hold true today? Or is this article outdated? (If it's outdated, can someone point me to a resource about current pitfalls)
Modern engines would not maintain unused variables in the outer scope.
Therefore, it doesn't matter if you set data = null before returning the inner function, because the inner function does not depend on ("close over") data.
If the inner function did depend on data--perhaps it returns it--then setting data = null is certainly not what you want to, because then, well, it would be null instead of having its original value!
Assuming the inner function does depend on data, then yes, as long as inner is being pointed to (referred to by) something, then the value of data will have to be kept around. But, that's what you are saying you want! How can you have something available without having it be available?
Remember that at some point the variable which holds the return value of f() will itself go out of scope. At that point, at least until f() is called again, data will be garbage collected.
The general rule is that you don't need to worry about memory and leaks with JavaScript. That's the whole point of GC. The garbage collector does an excellent job of identifying what is needed and what is not needed, and keeping the former and garbage collecting the latter.
You may want to consider the following example:
function foo() {
var x = 1;
return function() { debugger; return 1; };
}
function bar() {
var x = 1;
return function() { debugger; return x; };
}
foo()();
bar()();
And examine its execution in Chrome devtools variable window. When the debugger stops in the inner function of foo, note that x is not present as a local variable or as a closure. For all practical purposes, it does not exist.
When the debugger stops in the inner function of bar, we see the variable x, because it had to be preserved so as to be accessible in order to be returned.
Does this hold true today? Or is this article outdated?
No, it doesn't, and yes, it is. The article is four years old, which is a lifetime in the web world. I have no way to know if jQuery still is subject to leaks, but I'd be surprised if it were, and if so, there's an easy enough way to avoid them--don't use jQuery. The leaks the article's author mentions related to DOM loops and event handlers are not present in modern browsers, by which I mean IE10 (more likely IE9) and above. I'd suggest finding a more up-to-date reference if you really want to understand about memory leaks. Actually, I'd suggest you mainly stop worrying about memory leaks. They occur only in very specialized situations. It's hard to find much on the topic on the web these days for that precise reason. Here's one article I found: http://point.davidglasser.net/2013/06/27/surprising-javascript-memory-leak.html.
Just in addition to to #torazaburo's excellent answer, it is worth pointing out that the examples in that tutorial are not leaks. A leak what happens when a program deletes a reference to something but does not release the memory it consumes.
The last time I remember that JS developers had to really worry about genuine leaks was when Internet Explorer (6 and 7 I think) used separate memory management for the DOM and for JS. Because of this, it was possible to bind an onclick event to a button, destroy the button, and still have the event handler stranded in memory -- forever (or until the browser crashed or was closed by the user). You couldn't trigger the handler or release it after the fact. It just sat on the stack, taking up room. So if you had a long-lived webapp or a webpage that created and destroyed a lot of DOM elements, you had to be super diligent to always unbind events before destroying them.
I've also run into a few annoying leaks in iOS but these were all bugs and were (eventually) patched by Apple.
That said, a good developer needs to keep resource management in mind when writing code. Consider these two constructors:
function F() {
var data = "One megabyte of data";
this.inner = new function () {
return data;
}
}
var G = function () {};
G.prototype.data = "One megabyte of data";
G.prototype.inner = function () {
return this.data;
};
If you were to create a thousand instances of F, the browser would have to allocate an extra gigabyte of memory for all those copies of the huge string. And every time you deleted an instance, you might get some onscreen jankiness when the GC eventually recovered that ram. On the other hand, if you made a thousand instances of G, the huge string would be created once and reused by every instance. That is a huge performance boost.
But the advantage of F is that the huge string is essentially private. No other code outside of the constructor would be able to access that string directly. Because of that, each instance of F could mutate that string as much as it wanted and you'd never have to worry about causing problems for other instances.
On the other hand, the huge string in G is out there for anyone to change. Other instances could change it, and any code that shares the same scope as G could too.
So in this case, there is a trade-off between resource use and security.
Related
I have javascript web application which abnormally consumes more than 4gb of ram memory, when i launch application initially the memory consumption would be 700 to 800MB while doing any action on application some time longer immediately ram memory consumption is spike up.
what could be the root cause of it and how could i make my application to consume 400 to 500MB of ram.
It's impossible to answer your question, it's broad and we don't know your code (and we won't read it all for obvious reasons). But I think you should read this article on javascript optimisation on the Google Chrome développer website.
You should analyse which functions use the most memory and pin point the problem to find a possible memory leak and/or optimise the code.
https://developers.google.com/speed/articles/optimizing-javascript
Optimizing JavaScript code
Authors: Gregory Baker, Software Engineer on GMail & Erik Arvidsson,
Software Engineer on Google Chrome
Recommended experience: Working knowledge of JavaScript
Client-side scripting can make your application dynamic and active,
but the browser's interpretation of this code can itself introduce
inefficiencies, and the performance of different constructs varies
from client to client. Here we discuss a few tips and best practices
to optimize your JavaScript code.
Defining class methods
The following is inefficient, as each time a instance of baz.Bar is
constructed, a new function and closure is created for foo:
baz.Bar = function() { // constructor body this.foo = function() {
// method body }; } The preferred approach is:
baz.Bar = function() { // constructor body };
baz.Bar.prototype.foo = function() { // method body }; With this
approach, no matter how many instances of baz.Bar are constructed,
only a single function is ever created for foo, and no closures are
created.
Initializing instance variables
Place instance variable declaration/initialization on the prototype
for instance variables with value type (rather than reference type)
initialization values (i.e. values of type number, Boolean, null,
undefined, or string). This avoids unnecessarily running the
initialization code each time the constructor is called. (This can't
be done for instance variables whose initial value is dependent on
arguments to the constructor, or some other state at time of
construction.)
For example, instead of:
foo.Bar = function() { this.prop1_ = 4; this.prop2_ = true;
this.prop3_ = []; this.prop4_ = 'blah'; }; Use:
foo.Bar = function() { this.prop3_ = []; };
foo.Bar.prototype.prop1_ = 4;
foo.Bar.prototype.prop2_ = true;
foo.Bar.prototype.prop4_ = 'blah'; Avoiding pitfalls with closures
Closures are a powerful and useful feature of JavaScript; however,
they have several drawbacks, including:
They are the most common source of memory leaks. Creating a closure is
significantly slower than creating an inner function without a
closure, and much slower than reusing a static function. For example:
function setupAlertTimeout() { var msg = 'Message to alert';
window.setTimeout(function() { alert(msg); }, 100); } is slower than:
function setupAlertTimeout() { window.setTimeout(function() {
var msg = 'Message to alert';
alert(msg); }, 100); } which is slower than:
function alertMsg() { var msg = 'Message to alert'; alert(msg); }
function setupAlertTimeout() { window.setTimeout(alertMsg, 100); }
They add a level to the scope chain. When the browser resolves
properties, each level of the scope chain must be checked. In the
following example:
var a = 'a';
function createFunctionWithClosure() { var b = 'b'; return
function () {
var c = 'c';
a;
b;
c; }; }
var f = createFunctionWithClosure(); f(); when f is invoked,
referencing a is slower than referencing b, which is slower than
referencing c. See IE+JScript Performance Recommendations Part 3:
JavaScript Code inefficiencies for information on when to use closures
with IE.
Avoiding with
Avoid using with in your code. It has a negative impact on
performance, as it modifies the scope chain, making it more expensive
to look up variables in other scopes.
Avoiding browser memory leaks
Memory leaks are an all too common problem with web applications, and
can result in huge performance hits. As the memory usage of the
browser grows, your web application, along with the rest of the user's
system, slows down. The most common memory leaks for web applications
involve circular references between the JavaScript script engine and
the browsers' C++ objects' implementing the DOM (e.g. between the
JavaScript script engine and Internet Explorer's COM infrastructure,
or between the JavaScript engine and Firefox XPCOM infrastructure).
Here are some rules of thumb for avoiding memory leaks:
Use an event system for attaching event handlers
The most common circular reference pattern [ DOM element --> event
handler --> closure scope --> DOM ] element is discussed in this MSDN
blog post. To avoid this problem, use one of the well-tested event
systems for attaching event handlers, such as those in Google doctype,
Dojo, or JQuery.
In addition, using inline event handlers can lead to another kind of
leak in IE. This is not the common circular reference type leak, but
rather a leak of an internal temporary anonymous script object. For
details, see the section on "DOM Insertion Order Leak Model" in
Understanding and Solving Internet Explorer Leak Patterns and and an
example in this JavaScript Kit tutorial.
Avoid expando properties
Expando properties are arbitrary JavaScript properties on DOM elements
and are a common source of circular references. You can use expando
properties without introducing memory leaks, but it is pretty easy to
introduce one by accident. The leak pattern here is [ DOM element -->
via expando--> intermediary object --> DOM element ]. The best thing
to do is to just avoid using them. If you do use them, only use values
with primitive types. If you do use non-primitive values, nullify the
expando property when it is no longer needed. See the section on
"Circular References" in Understanding and Solving Internet Explorer
Leak Patterns.
If I have a function within an object (a Backbone model in my case)...
doIt: function () {
var self = this,
result = null;
this.doMagic(function(){
result = self.doWizardry();
});
self = null;
return result
}
...do I need to set self as null as I've done here, in order to avoid memory leaks?
Bonus question, will the closure's reference to 'result' cause a memory leak too?
Any advice on improving the efficiency of this type of structure would be much appreciated!
(Hopefully obvious that this is not a real function, just illustrative)
Thanks!
No. In fact, setting self to null before this.doMamgic() is called will also ruin the variable self such that this.doMagic() won't be able to use it because its value will have been cleared when this.doMagic() is actually trying to use it some time later.
Self references in Javascript do not by themselves lead to memory leaks. The GC is smart enough to detect that. If a whole object is unreachable by other JS, it doesn't matter how many references the object has to itself inside the object.
I see no particular reason in this code why using the variable self would lead to a memory leak and doing something like this is a well-established pattern for storing state that a callback can use (just like you're trying to do).
As for general advice, the point of the doIt() function looks like it has issues. You appear to be trying to return the result value that was set by this.doMagic(), but this.doMagic() is not called while doIt() is executing, thus result will NEVER have a value when doIt() returns.
So, this whole structure appears flawed. To know what to recommend would require understand what you're trying to accomplish and how you are calling/using this code which you have not disclosed.
I am finding myself rather confused regarding javascript garbage collection and how to best encourage it.
What I would like to know is related to a particular pattern. I am not interested in whether the pattern itself is considered a good or bad idea, I am simply interested in how a browsers garbage collector would respond, i.e would the references be freed and collected or would it cause leaks.
Imagine this pattern:
TEST = {
init : function(){
this.cache = {
element : $('#element')
};
},
func1 : function(){
this.cache.element.show();
},
func2 : function(){
TEST.cache.element.show();
},
func3 : function(){
var self = this;
self.cache.element.show();
},
func4 : function(){
var element = this.cache.element;
element.show();
}
func5 : function(){
this.auxfunc(this.cache.element);
}
auxfunc1 : function(el){
el.show();
}
func6 : function(){
var el = getElement();
el.show();
}
getElement : function(){
return this.cache.element;
}
}
Now imagine that on page load TEST.init() is called;
Then later at various times the various functions are called.
What I would like to know is if caching elements or objects or anything else upon initialization and referring to them throughout the lifetime of an application, in the manner shown above, effects a browsers garbage collector positively or negatively.
Is there any difference? Which method best encourages garbage collection? Do they cause leaks? Are there any circular references? if so where?
This code, in itself, shouldn't cause any memory leaks. Especially not in modern browsers. It's just an object, like you have tons of others in any script. It all depends on where, how, and how long you reference it.
The basic rule is that, whenever an object is no longer referenced anywhere in the code (directly/by variable or indirectly/ through closure accessing a scope), the GC will flag and swipe.
If you use the above code, and then assign something else to TEST the object literal it referenced could be GC'ed, if no other variable references the original object.
Of course, predicting memory leaks in JS is an inexact science. In my experience, they're not nearly as common as some would have you believe. Firebug, Chrome's console (profiler) and IE debugger get you along a long way.
Some time ago I did some more digging into this matter resulting in this question. Perhaps some links, and findings are helpful to you...
If not here's a couple of tips to avoid the obvious leaks:
Don't use global variables (they don't actually leak memory permanently, but do so, for as long as your script runs).
Don't attach event handlers to the global object (window.onload ==> leaks mem in IE <9 because the global object is never fully unloaded, hence the event handler isn't GC'ed)
Just wrap your script in a huge IIFE, and use strict mode whenever possible. That way, you create a scope that can be GC'ed in its entirety on unload.
Test, test and test again. Don't believe every blogpost you read on the subject! If something was an issue last year, that needn't be the case today. This answer might not be 100% accurate anymore by the time you read this, or because just this morning some miracle-patch for JS GC'ing was written by erm... Paris Hilton or some other alien life-form.
Oh, and to answer your in-comment question: "But what concerns me is if each time i call this.cache.element, is it creating a new reference within that functions scope ON TOP of the original cache reference which will not be garbage collected?"
The answer is no. Because this will reference the TEST object, and the init function assigns the object a property cahche, that in itself is another object literal with 1 property referencing a jQ object. That property (cache) and all that is accessible through it will sit in memory right until you either delete TEST.cache or delete TEST. if you were to create var cahce = {...}; that object would be GC'ed when the ini function returns, because a variable cannot outlive its scope, except for when you're using closures and exposing certain variables indirectly.
I'm trying to wrap my head around private variables in Javascript, temporary variables, and the GC. However, I can't quite figure out what would happen in the following situation:
MyClass = function() {
this.myProp = new createjs.Shape();
var tempVar = this.myProp.graphics;
tempVar.rect(0, 0, 10, 100);
tempVar = null;
var isDisposed = false;
this.dispose = function() {
if (isDisposed) return;
isDisposed = true;
}
}
var anInstance = new myClass();
My intention was to have isDisposed represent a private status variable, and tempVar be a use-and-throw variable.
Would tempVar get marked for GC? Would isDisposed be marked for GC too? How is the GC to know when I'm trying to declare a temporary variable meant for disposal, and when I'm trying to have a private variable within the object?
I tried to test the following in Chrome, and it seems as if tempVar never gets GC-ed as long as an instance of myClass exists. So I'm not sure what to believe now. I am incredulous that every single local variable that I create for temporary usage will exist in scope for the lifetime of the object.
Javascript does not have strongly typed objects. By setting tempVar to null, you're not declaring that you don't want to use it any more or marking it for collection as in Java or C#, you're merely assigning it a (perfectly valid) value. It's a trap to begin thinking that just because you made tempVar an "instance" of an object, that the variable is in fact an object and can be treated as such for its whole lifetime.
Basically, variables are just variables in Javascript. They can contain anything. It's like VB or VBScript in that regard. Scalars do undergo boxing in many cases (as in 'a|c'.split('|') making the string into a String) but for the most part, forget that. Functions are first-class objects meaning you can assign them to variables, return them from functions, pass them as parameters, and so on.
Now, to actually destroy something in Javascript, you either remove all references to it (as in the case of an object) or, in the case of an object's properties, you can remove them like this:
delete obj.propertyname;
// or //
delete obj[varContainingPropertyName];
To expand on that point, the following two code snippets achieve identical results:
function abc() {window.alert('blah');}
var abc = function() {window.alert('blah');}
Both create a local variable called abc that happens to be a function. The first one can be thought of as a shortcut for the second one.
However, according to this excellent article on deleting that you brought to my attention, you cannot delete local variables (including functions, which are really also local variables). There are exceptions (if the variable was created using eval, or it is in Global scope and you're not using IE <= 8, or you ARE using IE <= 8 and the variable was created in Global scope implicitly as in x = 1 which is technically a huge bug), so read the article for full details on delete, please.
Another key thing that may be of use to you is to know that in Javascript only functions have scope (and the window in browser implementations or whatever the global scope is in other implementations). Non-function objects and code blocks enclosed in { } do not have scope (and I say it this way since the prototype of Function is Object, so functions are objects too, but special ones). This means that, for example, considering the following code:
function doSomething(x) {
if (x > 0) {
var y = 1;
}
return y;
}
This will return 1 when executed with x > 0 because the scope of variable y is the function, not the block. So in fact it's wrong and misleading to put the var declaration in the block since it is in effect (though perhaps not true practice) hoisted to the function scope.
You should read up on closures in javascript (I cannot vouch for the quality of that link). Doing so will probably help. Any time a variable's function scope is maintained anywhere, then all the function's private variables are also. The best you can do is set them to undefined (which is more "nothing" than "null" is in Javascript) which will release any object references they have, but will not truly deallocate the variable to make it available for GC.
As for general GCing gotchas, be aware that if a function has a closure over a DOM element, and a DOM element somewhere also references that function, neither will be GCed until the page is unloaded or you break the circular reference. In some--or all?--versions of IE, such a circular reference will cause a memory leak and it will never be GCed until the browser is closed.
To try to answer your questions more directly:
tempVar will not be marked for GC until the function it is part of has all references released, because it is a local variable, and local variables in Javascript cannot be deleted.
isDisposed has the same qualities as tempVar.
There is no distinction in Javascript for "temporary variables meant for disposal". In newer versions of ECMAScript, there are actual getters and setters available, to define public (or private?) properties of a function.
A browser's console may provide you with misleading results, as discussed in the article on deleting with Firefox.
It's true, as incredible as it may be, that in Javascript, so long as a variable exists within a closure, that variable remains instantiated. This is not normally a problem, and I have not experienced browsers truly running out of memory due to tiny variables lying around un-garbage-collected. Set a variable to undefined when done with it, and be at ease--I sincerely doubt you will ever experience a problem. If you are concerned, then declare a local object var tmpObj = {tempVar: 'something'}; and when done with it you can issue a delete tmpObj.tempVar;. But in my opinion this will needlessly clutter your code.
Basically, my suggestion is to understand that in coming from other programming languages, you have preconceived notions about how a programming language ought to work. Some of those notions may have validity in terms of the ideal programming language. However, it is probably best if you relinquish those notions and just embrace, at least for now, how Javascript actually works. Until you are truly experienced enough to confidently violate the advice of those who have gone before you (such as I) then you're at greater risk of introducing harmful anti-patterns into your Javascript code than you are likely to be correcting any serious deficit in the language. Not having to Dispose() stuff could be really good news--it's this nasty pervasive task that Javascript simply doesn't require from you, so you can spend more time writing functionality and less time managing the lifetime of variables. Win!
I hope you take my words as kindly as they are meant. I don't by any means consider myself a Javascript expert--just that I have some experience and a solid competence in understanding how to use it and what the pitfalls are.
Thanks for listening!
I need some help here to undestand how this works (or does not, for that matter).
In a web page, I create a click event listener for a node.
Within the listener, I create an instance of some random class, which sets the node as property within itself. So, if var classInstance is the instance, I can access the node as something like classInstance.rootNode.
When the listener fires, I setup an ajax request, keep classInstance in closure and pass along the ajax response to classInstance and use it to perhaps modify the rootNode's style or content or whatever.
My question is, once I'm done with classInstance, assuming nothing else references it and by itself, it holds nothing else in its own closure, will the garbage collector dispose of it? If not, how do I mark it for disposal?
In response to #Beetroot-Beetroot's doubts (which, admittedly, I have, too), I did some more digging. I set up this fiddle, and used the chrome dev-tools' timeline and this article as a guideline. In the fiddle, two almost identical handlers create a closure with 2 date objects. The first only references a, the second references both a and b. Though in both cases only a can ever really be exposed (hard-coded values), the first closure uses significantly less memory. Whether or not this is down to JIC (just in time compilation) or V8's JS optimization wizardry, I can't say for sure. But from what I've read, I'd say it's V8's GC that deallocates b when the tst function returns, which it can't in the second case (bar references b when tst2 returns). I get the feeling that this isn't that outlandish, and I wouldn't at all be surprised to find out that FF and even IE would work similarly. Just added this, perhaps irrelevant, update for completeness' sake and because I feel as though a link to google's documentation of the dev-tools is an added value of sorts.
It sort of depends, as a simple rule of thumb: as long as you can't reference the classInstance variable anymore, it should be GC'ed, regardless of its own circular references. I've tested quite a lot of constructions, similar to the one you describe here. Perhaps it's worth a lookI've found that closures and mem-leaks aren't that common or easy to get by (at least, not anymore).
But as the accepted answer says: it's nigh impossible to know when what code will leak. Reading over your question again, I'd say: no, you're not going to leak memory: the classInstance variable wasn't created in the global scope, but it's being passed to various functions (and therefore various scopes). These scopes disintegrate each time the function returns. classInstance won't be GC'ed if it's been passed to another function/scope. But as soon as the last function that references classInstance returns, the object is marked for GC. Sure it might be a circular reference, but it's a reference that cannot be accessed from anywhere but its own scope. You can't really call that a closure, either: closures happen when there is some form of exposure to the outer scope, which is not happening in your example.
I'm rubbish at explaining stuff like this, but just to recap:
var foo = (function()
{
var a, b, c, d;
return function()
{
return a;
}
})();
The GC will deallocate the mem b,c and d reference: they've gone out of scope, there's no way to access them...
var foo = (function()
{
var a, b, c, d;
return function()
{
a.getB = function()
{
return b;
}
a.getSelf = function()
{
return a;//or return this;
}
return a;
}
})();
//some code
foo = new Date();//
In this case, b won't get GC'ed either, for obvious reasons. foo exposes a and b, where a is an object that contains a circular reference. Though as soon as foo = new Date(), foo loses any reference to a. Sure, a still references itself, but a is no longer exposed: it can reference whatever it bloody well likes. Most browsers won't care and will GC a and b. In fact, I've checked and Chrome, FF, and IE8 all GC the code above perfectly... no worries, then.
I'm not an expert on this issue, but I'm pretty sure the GC will not dispose of it. In fact, it probably never will, because you've created a circular reference between the event listener and the DOM node. To allow it to be garbage-collected, you should set one or both of those references (the event listener and/or rootNode) to undefined or null.
Still, I'd only worry about this if you're creating many of these classInstances or if it can be created several times over the page's lifetime. Otherwise it's an unnecessary optimization.