Pattern for no-allocation loops in JavaScript? - javascript

Say we're writing a browser app where smooth animation is critical. We know garbage collection can block execution long enough to cause a perceptible freeze, so we need to minimize the amount of garbage we create. To minimize garbage, we need to avoid memory allocation while the main animation loop is running.
But that execution path is strewn with loops:
var i = things.length; while (i--) { /* stuff */ }
for (var i = 0, len = things.length; i < len; i++) { /* stuff */ }
And their var statements allocate memory can allocate memory that the garbage collector may remove, which we want to avoid.
So, what is a good strategy for writing loop constructs in JavaScript that avoid allocating memory each one? I'm looking for a general solution, with pros and cons listed.
Here are three ideas I've come up with:
1.) Declare "top-level" vars for index and length; reuse them everywhere
We could declare app.i and app.length at the top, and reuse them again and again:
app.i = things.length; while (app.i--) { /* stuff */ }
for (app.i = 0; app.i < app.length; app.i++) { /* stuff */ }
Pros: Simple enough to implement. Cons: Performance hit by dereferencing the properties might mean a Pyrrhic victory. Might accidentally misuse/clobber properties and cause bugs.
2.) If array length is known, don't loop -- unroll
We might be guaranteed that an array has a certain number of elements. If we do know what the length will be in advance, we could manually unwind the loop in our program:
doSomethingWithThing(things[0]);
doSomethingWithThing(things[1]);
doSomethingWithThing(things[2]);
Pros: Efficient. Cons: Rarely possible in practice. Ugly? Annoying to change?
3.) Leverage closures, via the factory pattern
Write a factory function that returns a 'looper', a function that performs an action on the elements of a collection (a la _.each). The looper keeps private reference to index and length variables in the closure that is created. The looper must reset i and length each time it's called.
function buildLooper() {
var i, length;
return function(collection, functionToPerformOnEach) { /* implement me */ };
}
app.each = buildLooper();
app.each(things, doSomethingWithThing);
Pros: More functional, more idiomatic? Cons: Function calls add overhead. Closure access has shown to be slower than object look-up.

And their var statements allocate memory can allocate memory that the garbage collector may remove, which we want to avoid.
This is slightly misinformed. Simply using var does not allocate memory on the heap. When a function is called, each variable used in the function is allocated in advance on the stack. When the function completes execution, the stack frame is popped and the memory is immediately dereferenced.
Where garbage collection-related memory concerns become a problem is when you're allocating objects on the heap. That means any of the following:
Closures
Event listeners
Arrays
Objects
For the most part, anything where typeof foo returns "function" or "object" (or any of the new ES6 typeof return values) will generate an object on the heap. There's probably more that I can't think of right now.
The thing about objects on the heap is that they can refer to other objects on the heap. So for instance:
var x = {};
x.y = {};
delete x;
In the example above, the browser simply can't deallocate the slot for x, because the value contained within it is of variable size. It lives on the heap, where it could then point to other objects (in this case, the object at x.y). Another possibility is that there's a second reference to the same object:
var x = {};
window.foo = x;
delete x;
The browser simply can't remove the object at x from memory, since something else is still pointed at it.
So long story short, don't worry about removing variables, because they work perfectly well and are totally performant. Heap allocations are the real enemy when it comes to garbage collection, but even a few small heap allocations here and there won't hurt most apps.

Related

What is better: to create a new variable or to assign the value to an object field?

I wish to know what would be faster to implement.
I want to have a temporary variable that will be used for some calculations inside a function. The attacker and defender objects will be later used and everything created inside them should be deleted.
First, I have an approach of creating a temporary dmg variable to store the damages of attacker and defender.
var dmg;
dmg.attacker = 10;
dmg.defender = 10;
var battle = function (dmg, attacker, defender) {
//Some calculations using dmg.attacker and dmg.defender.
}
And a second approach, were I'm storing attacker and defender dmg inside them. There will be no problem if other part of the program catchs the attacker/defender object before the dmg has been deleted.
attacker.dmg = 10;
defender.dmg = 10;
var battle = function (attacker, defender) {
//Some calculations using attacker.dmg and defender.dmg.
delete attacker.dmg;
delete defender.dmg;
}
So, which implementation would be faster and why? Is there any other better options? I'm using Node 4 LTS, it there any nuances that I don't know about?
This is not the kind of thing for which performance should be the ultimate guiding factor, especially without a profiler in hand. Let maintainability and productivity be the guiding force here until you start measuring hotspots in hindsight.
That said, just as a general rule of thumb, the more local your state changes and accesses are, typically the faster they will be. More local accesses to local variables are preferable from a performance standpoint than more access to fewer but more global variables.
Local State is Fast
Optimizing compilers do their best when the most amount of information is readily available. Effective register allocation and instruction selection is easier when analyzing the local variables of a function than globals variables with a much broader scope than the function which could be modified and accessed anywhere.
The key to efficiency often revolves around loading from slower but bigger memory (DRAM,e.g.) into faster but smaller memory (L1 cache line and then register). Making code fast means keeping and using frequently-accessed memory as much as possible inside those faster but smaller forms of memory (register, e.g.). This is easier for the compiler to do when your variables have a very local scope, since it doesn't have to look outside that scope to see whether it needs to spill the variable to the stack or can keep it inside the register, for example.
So as a general rule of thumb, prefer more local state with shorter scopes to more global states with wider scopes. That not only tends to improve efficiency but also reduce human errors*.
* Note that this is opposite from an assembly mindset. In assembly, it's helpful to reuse registers as much as possible to avoid stack spills. In languages that have variables instead of direct register access, more local variables helps the compiler figure out what registers it can reuse.
Specific Example
In this specific case, adding members and removing them from an associative structure (objects fit this case in JS) tends to be more expensive than creating one and simply discarding it as a whole. These lines:
delete attacker.dmg;
delete defender.dmg;
... specifically tend to be more costly than constructing some temporary object and simply destroying it as a whole when you're finished with it than adding members to a more global object and then removing them when done.
As a plus, this should also be a little less error-prone so you get that bonus as well. As a second plus, assuming attacker and defender have a fairly broad scope, this function that creates this dmg variable would avoid side effects to those objects, and therefore would be thread-safe since it's only dealing with local states (assuming this is all it's doing and not modifying other globals).
If you're really fussy about it, it would be best to create attacker damage and defender damage as two separate scalars instead of aggregated into an object and pass both forms of damage to this battle function. But that's really degrading the code readability, and something you should only do with a profiler in your hand that tells you this is a top hotspot.
According to the result of the snippet below the first approach is much faster.
var dmg = {};
var battleDmg = function (dmg) {};
var start = new Date().getTime();
for(var i = 0; i < 100000; i++) {
dmg.attacker = 10;
dmg.defender = 10;
battleDmg(dmg);
}
console.log('dmg:' + (new Date().getTime() - start));
var attacker = {}, defender = {};
var battleAttackerVsDefender = function (attacker, defender) {
delete attacker.dmg;
delete defender.dmg;
};
start = new Date().getTime();
for(i = 0; i < 100000; i++) {
attacker.dmg = 10;
defender.dmg = 10;
battleAttackerVsDefender(attacker, defender);
}
console.log('a vs d:' + (new Date().getTime() - start));
I think it is because in the first case:
a single argument (instead of 2 arguments) is passed to the function
no delete operation (instead of 2 operations) is performed

Javascript Garbage Collection. Creating Objects and Vars?

I am currently building a game in Javascript. After some testing, I was beginning to notice occasional lag which could only be caused by the GC kicking in. II decided to run a profile on it. The result shows that the GC is in fact the culprit:
I read that creating new objects causes a lot of GC. I am wondering if something like this:
var x = [];
Creates any Garbage as well, since primitive types in Java don't do this. Since there are no real types in Javascript, I am unsure. Furthermore, which of these is the best for creating the least amount of garbage:
Option 1:
function do() {
var x = [];
...
}
Option 2:
var x = [];
function do() {
x = [];
...
}
Option 3:
function do() {
x = [];
...
}
Or Option 4:
function do() {
var x = [];
...
delete x;
}
Option 5:
var x = [];
function do() {
x.length = 0;
...
}
The do function is called 30 Times a Second in my case. And it runs several operations on the array.
I am wondering this, because I just made all of my variables global to try to prevent them from being collected by the GC, but the GC did not change much.
Could you also provide some common examples of things that create a lot of Garbage and some alternatives.
Thank you.
Can you also show the memory of timeline? If you have GC issues those should be blatantly obvious there as you would see a sawtooth wave graph. Whenever the graph drops, that's the GC kicking in, blocking your thread to empty our the trash and that's the main cause of memory related freezing
Example of sawtooth wave graph (the blue graph is memory):
Generally speaking, which object instantiation do you use does not matter than much since the memory impact of a [] is minimal, what you're interested in is the content of the arrays, but to go through your options:
Option 1: This is generally OK, with one consideration: Closures. You should try to avoid closures as much as possible since they're generally the main cause for GC.
Option 2: Avoid referencing things outside of your scope, it doesn't help memory-wise and it makes your app a bit slower since it has to go up the closure chain to find the match. No benefit to doing this
Option 3: never ever do this, you always want to define x somewhere otherwise you're purposely leaking into the global scope and therefore it will potentially never be GCed
Option 4: This is actually an interesting one. normally delete x does not do anything since delete only acts on properties of an object. In case you didn't know, delete actually returns a boolean that signifies whether the object has been deleted or not, so you can run this example in the chrome console:
function tmp () {
var a = 1;
delete a; // false
console.log('a=', a) // 1
b = 2;
delete b; // true !!!
console.log('b=', b) // Exception
}
tmp();
What the?! well when you say b = 2 (without the var) it's the same thing as writing window.b = 2 so when you're delete b, you're basically doing delete window.b which satisfy the "only delete property clause".
Still, DON'T DO THIS!
Option 5: This one actually saves you a tiny tiny bit of memory since it doesn't have to GC x, HOWEVER: it does have to GC all the content of x which is generally much greater in size that x itself therefore it won't make a difference
This is a fantastic article if you want to learn more about memory profiling + common memory performance pitfalls: http://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript/

javascript delete object safe for memory leak

this is my code, I do not know if it good for prevent leaking memory ? help and how can I test for leaking memory?
var Test = function () {
this.ar = [];
this.List = function () {
return this.ar;
}
this.Add = function (str) {
this.ar.push(str);
}
}
use:
var t = new Test();
t.Add("One");
t.Add("Two");
t.Add("Three");
alert(JSON.stringify(t.List()));
t = undefined;
alert(JSON.stringify(t.List() ));
Setting t to undefined will clear that reference to the object. If there are no other references to that object in your code, then the garbage collector will indeed free up that Test() object. That's how things work in javascript. You don't delete an object, you just clear any references to it. When all references are gone, the object is available for garbage collection.
The actual delete keyword in javascript is used only to remove a property from an object as in delete t.list.
Different browsers have different tools available for keeping track of memory usage. The most universal, blackbox way I know of for a test is to run a cycle over and over again where you assign very large objects (I often use big strings) into your test (to consume noticable amounts of memory) with some sort of setTimeout() in between some number of runs (to let the garbage collector have some cycles) and then just watch the overall memory usage of the browser. As long as the overall memory usage doesn't keep going up and up as you keep doing more and more runs then you must not have a noticeable leak.
Individual browsers may have more comprehensive measuring tools available. Info here for Chrome.

Trying to Understand Javascript Closures + Memory Leaks

I've been reading up a lot on closures in Javascript. I come from a more traditional (C, C++, etc) background and understand call stacks and such, but I am having troubles with memory usage in Javascript. Here's a (simplified) test case I set up:
function updateLater(){
console.log('timer update');
var params = new Object();
for(var y=0; y<1000000; y++){
params[y] = {'test':y};
}
}
Alternatively, I've also tried using a closure:
function updateLaterClosure(){
return (function(){
console.log('timer update');
var params = new Object()
for(var y=0; y<1000000; y++)
{
params[y] = {'test':y};
}
});
}
Then, I set an interval to run the function...
setInterval(updateLater, 5000); // or var c = updateLaterClosure(); setInterval(c,5000);
The first time the timer runs, the Memory Usage jumps form 50MB to 75MB (according to Chrome's Task Manager). The second time it goes above 100MB. Occasionally it drops back down a little, but never below 75MB.
Check it out yourself: https://local.phazm.com:4435/Streamified/extension/branches/lib/test.html
Clearly, params is not being fully garbage collected, because the memory from the first timer call is not being freed... yet, neither is it adding 25MB of memory on EACH call, so it is not as if the garbage collection is NEVER happening... it almost seems as though one instance of "params" is always being kept around. I've tried setting up a sub-closure and other things... no dice.
What is MOST disturbing, though, is that the memory usage trends upwards. It might "just" be 75MB for now, but leave it running for long enough (overnight) and it'll get to 500 MB.
Ideas?
Thanks!
Allocating 25mb causes a GC to happen. This GC cleans up the last instance but of course not the current. So you always have one instance around.
GC does not happen when the program is idle. It does not happen between your timer calls so the memory stays around.
That is not even a closure. A closure is when you return something from a function, like an array, function, object or anything that can contain references, and it carries with it all the local members of that function.
what you have there is just a case of a very long loop that is building a very big object. and maybe your memory does not get reclaimed as fast as you are building the huge objects.

Null and delete() in regards to garbage collection

Anyhow, If I were to write something like:
var h = 5;
delete h;
...I'd be eliminating the reference, but not the memory.
Now, if I set the variable to null, would that replace the memory with the null object?
var h = 5;
h = null;
If so, wouldn't it be better to not only delete() the reference, but also replace the memory with a null object, for better memory optimization?
var h = 5;
h = null;
delete h;
If I want to create a bucket-load of dynamic objects in a long and complex script, what's the best way to get rid of, or otherwise induce the garbage collector to eliminate, objects? Because in addition to just eliminating references, I had read that you could hint the collector to free memory if it was occupied by null...
There's no destroy. You're probably thinking about delete, but delete can't be used to delete variables, only properties. (Although currently browsers let you get away with it, with varying results.) You can delete global variables by removing them from window, but not locals.
Anyway you don't need to think about this sort of stuff in JavaScript. Set a variable to null and if there are no more variables pointing to the same object, it'll get garbage-collected at some point in the near future. The amount of space taken up by the record of the variable pointing to null is tiny and not worth worrying about. Unless you are making a deliberate closure it'll fall out of scope anyway when the local function exits, becoming eligable for GC.
I had read that you could hint the collector to free memory if it was occupied by null...
Nope. You're just removing the references, the GC will pick up the now orphaned objects and free the memory at its own leisure. You don't get any say in the matter.
Simply drop all references to the buckload and let the garbage collection do the magic.

Categories