Memory leaks in SPA built with Knockout.js

Dima Kuzmich
3 min readApr 28, 2014

--

The Problem:

When we build large SPA applications with MV* frameworks that have data bindings, such as Knockout.js, we actually create connection between our JS models and DOM elements. Those connections may be done in number of ways, but the bottom line is that DOM elements may have references to our models. In Knockout, for example, every element that has bindings, has relation to closure object that stores reference to binding context. This binding context has pointer to our model. Now, with this in mind, we can see the problem that will come. If we simply remove DOM element that has bindings, a closure from above will still hold a pointer to our model and as a result will be never released from memory. This problem is especially critical in SPA applications as to change page we simply swap inner HTML of some container and never do full reload of the page.

Detection:

To detect an above problem in SPA with Knockout we don’t need to do much. If we bind our models and never unbind them, we almost certain have a leaks. However, I’ll show a way to ensure it with Chrome DevTools.

We need to run our application and to open a DevTools (F12 for windows users). I created a simple application with Knockout and Sammy.js for routing. Download it here. After we run an application we need to take a heap snapshot. Press ‘Profiles’ tab in DevTools, check ‘Take Heap Snapshot’ and press ‘Take Snapshot’

Image

After that change between pages 1 and 2 for 10 times and take another snapshot. Now, when we have these two snapshots, we can compare them. We simply switch the mode of snapshot preview to ‘Comparison’

Image

While in comparison mode, we can sort our results by ‘# Delta’ field. This field says how many objects from particular type are living now in memory. You can also check how many new objects was created and how many objects was released by looking at ‘# New’ and ‘# Deleted’ fields respectively. What we are looking now are the objects that created and never released. In my test application is very simple. We know that we visited each page for 5 times, so I will look for an objects that have 5 in ‘Delta’ field.

Image

As we can see, neither VM1 nor VM2 was released during our session.

Solution:

The solution for this problem, is very simple. As I said before, we only need to release bindingContext object of DOM node that we want to remove. Knockout provides us with number of methods that could be useful in this situation. We can use a ko.cleanNode(element) method before we remove an HTML or we can use ko.removeNode(element), that cleans Node and also removes it. No matter which way we are choosing to use, we need always remember — If we created a bindings, we must to unbind them!

--

--