Random thoughts on JavaScript performance, garbage collection, and object pooling

Let’s talk about garbage collection.

I love JavaScript, but I wish it gave me more control over these things. I am on a quest to minimize garbage. Last week’s Sthlm.js meetup gave me some more insight, at least in regards to Chrome. Paul Lewis gave a talk that covered garbage collection in part. You can see it here.

This post is more for me to organize my thoughts and collect what I understand about garbage collection and performance so far. Or parts of it, anyway. Some of this information may not be fully fleshed out and may not even be accurate (like I said, it’s performance and GC as I currently understand them). So if you notice anything that is blatantly wrong, or even debatable, please let me know. The vast majority of this info will focus on the Chrome browser, but will likely apply to others as well.

V8

Let’s start with V8 - the JavaScript engine that ships with Chrome. V8 works by compiling JavaScript to machine code. During this process the code is optimized…and sometimes deoptimized…at runtime. Deoptimization is bad and if you write code that needs to be deoptimized you should feel bad.

What V8 does with your code

If V8 notices recurring patterns in your code (eg: the same type for a specific variable), it will assume that this will not change and optimize this code. Optimization is good.

The garbage collector then comes along to clear out stuff that is no longer being used. If you have loose references hanging around to variables that are no longer being used, they will not be collected. During this time your actual game code is no longer running - it is put on hold until the garbage collection process is complete. So while garbage collection in itself is good, lengthy garbage collection is bad. The more garbage you have, the longer the collection process will take. Garbage is bad.

After garbage collection, your code continues to run. Dandy.

Deoptimization happens when V8 makes assumptions about your code and optimizes it, but then discovers that one instance when something is different. So if V8 expects x to always be an integer and suddenly you throw in a string, the code then needs to be deoptimized back to the original, slower, code.

V8 reclaims memory used by objects that are no longer required in a process known as garbage collection. To ensure fast object allocation, short garbage collection pauses, and no memory fragmentation V8 employs a stop-the-world, generational, accurate, garbage collector. This means that V8:

  • stops program execution when performing a garbage collection cycle.

  • processes only part of the object heap in most garbage collection cycles. This minimizes the impact of stopping the application.

  • always knows exactly where all objects and pointers are in memory. This avoids falsely identifying objects as pointers which can result in memory leaks.

In V8, the object heap is segmented into two parts: new space where objects are created, and old space to which objects surviving a garbage collection cycle are promoted. If an object is moved in a garbage collection cycle, V8 updates all pointers to the object.

Chrome V8 Design Elements - Garbage Collection

Everything I’ve read suggests that you don’t want to mess with the automatic garbage collection too much (not that you can) because it knows what it’s doing and you’ll do more harm than good. However, what we can do is put in the effort to not produce craploads of garbage in the first place.

Object pooling

This brings me to object pooling - having a pool of objects and reusing them as required as opposed to creating and removing objects all the time. I’m not sure how much benefit this will bring and I’ve read different opinions, but I’d like to start experimenting with object pools for ImpactJS entities. These objects are usually full of functions and variables and get created and killed on an ongoing basis throughout the game.

Examples of object pooling

If I was smart, I could have use object pooling for my snowflake and raindrop entities in Alien Tree. Instead of generating 300 snowflake instances on the fly and then killing them when they’re off screen, I could have generated those 300 instances at the beginning of the game and stored them away for repeated use.

In Promiscuous Flea, I could pool some flea NPC entities - create a set of 20 male and female flea instances and hide them until they’re actually required (ie a flea is born). Then reveal them and store them away again instead of killing them when they die. I want to finish the main functionality for the game first (it’s almost there anyway) and then play around with this if there’s time before the March deadline is up.

The downside

Object pooling introduces a degree of risk and a requirement to manage all of these objects. I’ll need to remember to reset the attributes of each flea entity instance before it’s reused, for example. Maybe I could come up with a small Impact plugin to manage these things better across different projects. We will see. Hopefully I’ll have time to do some experimentation on the March game.

comments powered by Disqus