5

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:

GC Profile

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.

  • 1
    No, primitives do not create any garbage in js. Make all your variables local to allow them to be cleaned up as soon as possible (making everything global is a horror!). Try to avoid closures, and everything else where new objects are created. Show us your actual code that you have problems with. – Bergi Oct 24 '15 at 12:55
  • 3
    Option 1 is to be preferred. Option 4 is basically the same, with a totally unnecessary assignment in the end. Option 4 with `delete` does not work, [`delete` does not destroy objects](http://perfectionkills.com/understanding-delete/). Options 2 and 3 do something entirely different, you hardly do want that - and global variables are an antipattern. – Bergi Oct 24 '15 at 12:57
  • My code is very similar to this, I tried to make it more general so it can be helpful to everyone. –  Oct 24 '15 at 12:57
  • No, your actual code probably actually does something. You're not even executing `do` in the snippets you've given. These "patterns" are far too generic to say anything useful about their GC behaviour. Is `do` something that's executed very often, or in a hot path? How/where else is `x` used after it is computed? Currently it would rather likely be subject to dead code elimination, and the only allocations are for the `do` function object and possibly the `x` global variable. – Bergi Oct 24 '15 at 13:40
  • Updated Question. I am calling the do function 30 times a second. –  Oct 24 '15 at 13:53
  • Related questions: [What is JavaScript garbage collection?](http://stackoverflow.com/q/864516/3345375) and [Best practices for reducing Garbage Collector activity in Javascript](http://stackoverflow.com/q/18364175/3345375) – jkdev Oct 25 '15 at 03:34
  • 1
    This blog post might also be helpful: [A Detailed Explanation of JavaScript Game Loops and Timing](http://www.isaacsukin.com/news/2015/01/detailed-explanation-javascript-game-loops-and-timing). And some more articles on [writing fast, memory-efficient JavaScript](http://www.smashingmagazine.com/2012/11/writing-fast-memory-efficient-javascript) and [JavaScript memory management](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management). – jkdev Oct 25 '15 at 03:36

1 Answers1

2

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):enter image description here

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/

Stefan
  • 3,962
  • 4
  • 34
  • 39