Measuring used JS heap size in the browser

Estimated Reading Time: 4 minutes

Part of the tools frontend developers have in their arsenal is the performance API. Part of it is the memory object. It can be used for various causes – from debugging performance through experimenting to performance budget monitoring.

A heap of tools
Photo by Ashim D’Silva on Unsplash

I’ve created an egghead lesson about this subject if you prefer a video tutorial: click here for the video

There are three pieces of information in the memory object:

jsHeapSizeLimit – the maximum amount of heap size that your JS engine can ask from the operating system.

totalJSHeapSize – the actual memory allocated by the JS engine from the operating system.

usedJSHeapSize – the active memory in the allocated heap.

The usage is pretty simple:

console.log(performance.memory.usedJSHeapSize);

will log the memory in bytes currently used by the JS engine. Something like this:

11900000

This feature is non standard. It is currently not available in firefox and safari.

https://caniuse.com/#feat=mdn-api_performance_memory

Units

Because most of us are more used to Megabyte units, we can easily log a Megabytes output:

console.log(`${performance.memory.usedJSHeapSize / Math.pow(1000, 2)} MB`);

Now we can get a nicer output:

11.9 MB

Comparing memory before and after

Our JS code creates and deletes objects and arrays all the time. We can set a before and after test to measure the memory intake.

For instance, let’s look at the following code:

Code snippet 1: Two arrays are created one after another, taking more and more memory in the JS heap. The first array is an array of floating numbers – taking roughly double the amount of memory the second integers array takes.

Open the console in the plnkr above (just click the console pane). Now press the Measure Memory button. You will see three measurements of memory:

  1. Before we’ve done anything
  2. After we’ve created an array of floats
  3. After we’ve created an array of integers

The result will look like this:

Figure 1: Memory logged to the console. Top – before allocating an array. Middle – after allocating an array of floating numbers. Bottom – after allocating another array of integers.

Figure1 clearly shows that an array of floats (middle row) took more memory than an array of integers (bottom row). An array of floats took 422.76567 – 123.546093 = 299.219577 MB. An array of integers took 521.969676 – 422.76567 = 99.204006 MB.

Of course the numbers will change every time you run the code – but they won’t change significantly.

Remember the Garbage Collector

The garbage collection (GC) is the periodical process that clears unneeded memory from the heap. For instance – if you allocated an array and then cleared it or created and object and discarded of it or just created variables in a function and it has finished its job.

I’ve written about GC in several articles before (also in regards to the object pool design pattern).

Let’s see another example for the workings of the GC:

Code snippet 2: Arrays are created inside functions. A timeout is set so that a GC might be called after both functions finish.

In the code above, open the terminal and click the start again. This time, the arrays creation is done inside functions. Once the functions finish, the arrays are no longer needed and they are marked for GC.

Here’s a result:

Figure 2: Results of running code snippet 2.

Note that each time you’ll get a different result due to the nature of the JS engine and garbage collection (you’d might get only one GC or two):

Figure 3: Showing results that exhibit only one GC.

Summary

In the above short article, we learned about the memory object in the Performance API.

We saw how we can measure the maximum heap size, the current heap size and the current memory used inside the heap by our running application.

We experimented a bit and saw the difference in memory taken by an array of integers vs. floats.

The same technique can be applied to take measurements from code running in production (using automation tools like pupeteer or cypress) and build some performance dashboard like we did at WalkMe.

If after a push to production there’s an increase in memory beyond a certain threshold, you can do something with it (log, revert, alert – whatever).

Finally, we saw we can use this tool to experiment and demonstrate JS principles like the garbage collector.

If you have other use cases or some cool stuff to show off – use the comments section below or get in touch with me. I’m always happy to learn!

Leave a Reply

Your email address will not be published. Required fields are marked *