Scirra cog

About Us

We're a London based startup that develops Construct 2, software that lets you make your own computer games!


Browse all our blog posts

Latest Blog Entries

We love brains!

Join us! Joiiinnn ussss! Mooooree brains!

How to write low garbage real-time Javascript

by Ashley | 15th, March 2012

Edit 27th March 2012: wow, this article went a long way, thanks for the great response! There has been some criticism of some of the techniques here, such as the use of 'delete'. I'm aware things like that can cause other slowdowns, we use it very very sparingly in our engine. As always everything involves tradeoffs and you have to use judgement to balance GC with other concerns. This is simply a list of techniques we've found useful in our engine and was not meant to be a complete reference. I hope it's still somehow useful though!

For HTML5 games written in Javascript, one of the biggest obstacles to a smooth experience is garbage collection (GC) pauses. Javascript doesn't have explicit memory management, meaning you create things but don't release them. Sooner or later the browser decides to clean up: execution is paused, the browser figures out which parts of memory are still currently in use, and then releases everything else. This blog post will go in to the technical details of avoiding GC overhead, which should also come in handy for any plugin or behavior developers working with Construct 2's Javascript SDK.

There are lots of techniques browsers can employ to reduce GC pauses, but if your code creates a lot of garbage, sooner or later it's going to have to pause and clean up. This results in zig-zag memory usage graphs, as objects are gradually created, then the browser suddenly cleans up. For example, below is a graph of Chrome's memory usage while playing Space Blaster.

Chrome garbage-collected memory usage

Zig-zag memory usage while playing a Javascript game. This can be mistaken for a memory leak, but is in fact the normal operation of Javascript.

Further, a game running at 60 fps only has 16ms to render each frame, and GC collection can easily take 100ms or more - resulting in a visible pause, or in even worse situations, a constantly choppy play experience. Therefore, for real-time Javascript code like game engines, the solution is to try and reach the point where you create nothing at all during a typical frame. This is surprisingly difficult, because there are many innocuous looking Javascript statements that actually create garbage, and they all have to be removed from the per-frame code path. In Construct 2 we've gone to great lengths to minimise the garbage overhead in the per-tick engine, but as you can see from the graph above there's still a small rate of object creation that Chrome is cleaning up every several seconds. Note it's only a small dip though - there isn't a large amount of memory being cleaned up. A taller, more extreme zig-zag would be a cause for concern. However it's probably good enough, since small collections are quicker, and the occasional small pause is not generally too noticable - and as we shall see, sometimes it's extremely difficult to avoid new allocations.

It's also important for third-party plugin and behavior developers to follow these guidelines. Otherwise, a badly written plugin can create lots of garbage and cause the game to become choppy, even though the main Construct 2 engine is very low-garbage.

Simple techniques

First of all, most obviously, the new keyword indicates an allocation, e.g. new Foo(). Where possible, try to create the object on startup, and simply re-use the same object for as long as possible.

Less obviously, there are three syntax shortcuts for common uses of new:

{} (creates a new object)
[] (creates a new array)
function () { ... } (creates a new function, which are also garbage-collected!)

For objects, avoid {} the same way you avoid new - try to recycle objects. Note this includes objects with properties like { "foo": "bar" }, which is also commonly used in functions to return multiple values at once. It may be better to write the return value to the same (global) object every time and return that - providing you document this carefully, since you can cause bugs if you keep referencing the returned object which will change on every call!

You can actually re-cycle an existing object (providing it has no prototype chain) by deleting all of its properties, restoring it to an empty object like {}. For this you can use the cr.wipe(obj) function, defined as:

// remove all own properties on obj,
effectively reverting it to a new object
cr.wipe = function (obj)
	for (var p in obj)
		if (obj.hasOwnProperty(p))
			delete obj[p];

So in some cases you can re-use an object by calling cr.wipe(obj) and adding properties again. Wiping an object may take longer on-the-spot than simply assigning {}, but in real-time code it's much more important to avoid building up garbage which will later result in a pause.

Assigning [] to an array is often used as a shorthand to clear it (e.g. arr = [];), but note this creates a new empty array and garbages the old one! It's better to write arr.length = 0; which has the same effect but while re-using the same array object.

Functions are a bit trickier. Functions are commonly created at startup and don't tend to be allocated at run-time so much - but this means it's easy to overlook the cases where they are dynamically created. One example is functions which return functions. The main game loop typically uses setTimeout or requestAnimationFrame to call a member function something like this:

setTimeout((function (self) { return function () {
self.tick(); }; })(this), 16);

This looks like a reasonable way to call this.tick() every 16 ms. However, it also means every tick it returns a new function! This can be avoided by storing the function permanently, like so:

// at startup
this.tickFunc = (function (self) { return function () {
self.tick(); }; })(this);

// in the tick() function
setTimeout(this.tickFunc, 16);

This re-uses the same function every tick rather than spawning a new one. The same idea can be applied anywhere else functions are returned or otherwise created at runtime.

Advanced techniques

As we progress further avoiding garbage becomes more difficult, since Javascript is so fundamentally designed around the GC. Many of the convenient library functions in Javascript also create new objects. There is not much you can do here but go back to the documentation and look up the return values. For example, the array slice() method returns a new array (based on a range in the original array, which remains untouched), string's substr returns a new string (based on a range of characters in the original string, which remains untouched), and so on. Calling these functions creates garbage, and all you can do is either not call them, or in extreme cases re-write the functions in a way which does not create garbage. For example in the Construct 2 engine, for various reasons a regular operation is to delete the element at an index from an array. This convenient snippet was originally used for this:

var sliced = arr.slice(index + 1);
arr.length = index;
arr.push.apply(arr, sliced);

However, slice() returns a new array object with the latter part of the array, and it becomes garbage after being copied back in (arr.push.apply). Since this was a hot spot for garbage creation in our engine, it was rewritten to an iterative version:

for (var i = index, len = arr.length - 1; i < len; i++)
	arr[i] = arr[i + 1];

arr.length = len;

Obviously rewriting a lot of library functions is a huge pain, so you have to carefully balance the needs of convenience versus garbage creation. If it's called many times per frame, you may well want to rewrite a library function yourself.

It can be tempting to use {} syntax to pass data along in recursive functions. This is better done with a single array representing a stack which you push and pop for each level of recursion. Better yet, don't actually pop the array - you'll garbage the last object in the array. Instead use a 'top index' variable which you simply decrement. Then instead of pushing, increment the top index and re-use the next object in the array if there is one, otherwise do a real push.

Also, avoid vector objects if at all possible (as in vector2 with x and y properties). While again it may be convenient to have functions return these objects so they can change or return both values at once, you can easily end up with hundreds of these created every frame, resulting in terrible GC performance. These functions must be separated out to work on each component separately, e.g. instead of getPosition() returning a vector2 object, have getX() and getY().

Sometimes you're stuck with a library which is a garbage nightmare. The Box2Dweb library is a prime example: it spawns hundreds of b2Vec2 objects every frame constantly spraying the browser with garbage, and can end up causing significant garbage collector pauses. The best thing to do in this situation is create a recycling cache. We've been testing a modified version of Box2D (Box2Dweb-closure) that does this and it seems to help alleviate (although not entirely solve) GC pauses. See the code for Get and Free in b2Vec2.js. There's an array called the 'free cache', and throughout the code if there's a b2Vec2 which is known to be no longer used, it is freed, which puts it in the free cache. When requesting a new b2Vec2, if there are any in the free cache they are re-used, otherwise a new one is allocated. It's not perfect, since by some measurements I made often only half the b2Vec2s created get recycled, but it does relieve the pressure on the GC helping there be less frequent pauses.


It's difficult avoiding garbage entirely in Javascript. The garbage-collection pattern is fundamentally at odds with the requirements of real-time software like games. It can also be a lot of work to eliminate garbage from Javascript code since there's a lot of straightforward code out there which has the side-effect of creating loads of garbage. However, with care and attention, it is possible to craft real-time Javascript with little to no garbage collector overhead, and this is essential for games and apps which need to be highly responsive.

Now follow us and share this



gvt 404 rep

How did you get that nice graph of memory usage in Chrome? I could really use that right about now.

Friday, March 16, 2012 at 9:07:45 PM
Ashley 199.8k rep

@qrfvrge, pools can work but if you forget to free the return value you get a big memory leak, or if you cycle a fixed buffer you probably are just postponing the same bugs you'd get from referencing the return value. It's a tradeoff, I guess there are different ways to approach it.

@gvt: in Chrome, press Ctrl Shift J, Timeline tab, hit Record.

Friday, March 16, 2012 at 9:39:53 PM
Trevor10 4,161 rep

"You can actually re-cycle an existing object (providing it has no prototype chain)"

You mean use Object.create(null); for all plugin created objects?

Also, judging by how "cr.wipe(obj)" works, does that mean plugin writers should not seal or freeze on their base objects?

Saturday, March 17, 2012 at 7:24:28 AM
Ashley 199.8k rep

@Trevor10, not sure where you got Object.create from, that wasn't part of the post! I was talking about {}. Also cr.wipe only works on "temporary" objects like those created with {}, you certainly shouldn't use it anywhere else. Seal and freeze isn't really much to do with GC.

Saturday, March 17, 2012 at 4:17:33 PM
Trevor10 4,161 rep

@Ashley Object.create(null) is the only way to create an object that has no prototype chain. An object literal will always have Object.prototype in its prototype chain.

As for cr.wipe, delete will not work on a property that has had its configurable field set to false. Seal and freeze set the configurable field of all of the properties in an object to false, which is why I was asking if we should avoid using those since they would cause cr.wipe to fail.

Saturday, March 17, 2012 at 5:36:13 PM
Velojet 21.2k rep

Interesting and useful. It brought back memories of discovering the use of FRE(x) in Applesoft BASIC to stop the program grinding to halt.

Sunday, March 18, 2012 at 3:01:52 AM
Ashley 199.8k rep

@Trevor10 - ah, I should have been clearer, I didn't really mean strictly no prototype chain, but objects which don't inherit beyond Object. As in, literally typing {}, which you also typically would not seal or freeze either.

Sunday, March 18, 2012 at 7:30:58 PM
Trevor10 4,161 rep

@Ashley Thank you for the clarification.

Monday, March 19, 2012 at 3:24:21 AM
rsanchez1 377 rep

Do you have numbers on how this has improved performance for a demo or game from before low garbage optimizations were applied to after they were applied?

Monday, March 19, 2012 at 5:17:24 AM
Ashley 199.8k rep

@rsanchez1 Unfortunately not I'm afraid, we did a lot of work on our engine over a few weeks and didn't make a measurement before we started (but we should've!) Would be interested in anyone elses figures with a before/after.

Monday, March 19, 2012 at 3:19:20 PM
emaz 527 rep

I'm very curious about the recursion alternative mentioned. I wonder if someone could care to share a code example of this?

Tuesday, March 20, 2012 at 8:49:16 AM
gnurizen 377 rep

This post makes the assumption that avoiding object allocation is necessary for performant realtime JS which isn't necessarily true and in fact for some benchmarks in the Java world the opposite became true as the JVM's got better.

Almost all JS impls these days have very responsive incremental collectors that probably make some of these optimizations unnecessary. Some data to back up the efficacy of these changes would be cool. Better yet some browser battle style benchmarks would be cool. Could your Space Blaster test be redone for the top 3 browsers with more detailed metrics?

Can pause times and frame rates be accurately measured so people can make changes in this vien in a measured manner?

Tuesday, March 20, 2012 at 1:25:46 PM
kirbysayshi 377 rep

I believe there is an error in your setTimeout example. It doesn't actually create a new function on every frame. This is easily testable:

setInterval((function (self) {
return function () {
})(this), 1000);

Your output should be:


var f = (function(){ return function(){ ... } )();

is the exact same (aside from keeping a reference in f) as:

setTimeout((function(){ return function(){ ... } )());

Now, if the code was actually:

setTimeout(function(){ return function(){ ... } ));

Then yes, that would create a new function every tick.

Unless I'm misunderstanding something here? Sometimes code snippets out of context are deceptive.

Wednesday, March 21, 2012 at 11:02:00 PM
farre 527 rep

Nice article!

I feel a need to object to the advice regarding 'delete' though. That 'delete' does not allocate memory is in no way guaranteed. Also, all major browsers use an optimization technique called property caching, and this use of 'delete' can be catastrophic for optimized property look-ups. This doesn't mean that you can't re-use objects though, but in that case you should only re-use objects that have the same set of properties. Then you can just call the constructor directly with [[Constructor]].apply(object_to_reuse, arguments_to_create_with) instead of new [[Constructor]](arguments_to_create_with) and you don't need to delete properties before-hand.

Monday, March 26, 2012 at 9:00:01 AM
leifenberg 427 rep

This makes sense in theory. I would expect some sort of benchmark from such a post to back it up. In my experience, a lot of the assumed optimizations don't really matter that much when actually put to a real life test.

Monday, March 26, 2012 at 3:54:16 PM

Leave a comment

Everyone is welcome to leave their thoughts! Register a new account or login.