Backbone.js And JavaScript Garbage Collection

A question was asked on Stack Overflow recently, and I provided an answer that I think is worth re-blogging here (while cleaning up the text / grammar). My answer goes in to a little bit of the idea behind a garbage collected language and gets in to some of the basics of how JavaScript knows when to clean up your “garbage” – that is, your objects that are no longer used. What I’m presenting here is an oversimplification of how JavaScript manages memory. However, these basic ideas should prove useful to people who want to do a better job of managing memory usage in JavaScript.

What does Backbone.js do with models that are not used anymore?

When it comes down to it, Backbone does not explicitly handle cleaning up objects for you. That responsibility falls 50/50 between you and the JavaScript runtime.

JavaScript is a garbage collected language like Java, C#, Ruby, and others. In a garbage collected language, an object that is still referenced by your application will not be cleaned up. The counter point is that when an object is no longer referenced by your application, it will be cleaned up. Therefore, de-reference your objects and allow the JavaScript runtime to clean up the memory when you no longer need those objects.

Variable References And Cleanup In JavaScript

When you create a variable, you can either scope that variable to a local function or as a global variable (with some additional tricks and patterns that I show in my JavaScript Scope screencast).

Global variables are not cleaned up by the garbage collector during the life of the page. You can leave a page open for days or weeks or infinitely, and any variable that was scoped to the JavaScript runtime global object will stick around the whole time. Globals are cleaned up is when you refresh the page, leave the HTML page behind entirely (such as navigating to a different page and force the browser to load the new page from the server, doing a complete server refresh) or closing the browser or browser tab.

Function scoped variables are cleaned up when the variable falls out of scope. That is, when the function has exited and there are no more references to it, the variable can be cleaned up.

There are a few exceptions to this:

  • Returned values from functions
  • Closures
  • Object attributes and methods
  • Callback functions and DOM events

Ok, calling these “exceptions” is stretching it a bit. These types of references still fall under the same rules, but some additional tricks are used by the JavaScript run time to hold on to the references longer than you might expect.

Return Values

A return value is held in your app by assigning the return value to another variable. A return value falls under the same general rules, but the variable is now in a different function or attached to the global object. Once that variable goes out of scope, it can be cleaned up.

Closures

A closure – while a powerful and often used tool in JavaScript – is basically a controlled memory leak. A closure allows a parent scope to provide values that a nested scope can access – even when the parent scope has exited and nothing else references it. When the nested scope hangs around and has a closure on a variable from the original parent scope, that variable hangs around with it. Once the nested scope is cleaned up, the parent’s closured variable is allowed to be cleaned up (assuming nothing else is holding on to it).

Object Attributes And Methods

Objects with attributes and methods fall under the same rules. An object can reference another object or function by having an attribute assigned to it: myObj.foo = thatObj. In this case, any variable that you assign to the object will now live with that object. You can remove the reference from the attribute at any time, or let the object fall out of scope / reference to clean this up.

Callbacks

Callback functions are handed around as function pointers, or variables that are the actual function (to over-simplify things, again). When you pass a callback function somewhere, the original scope / object that had the callback may still be holding on to it. Additionally, the code that the callback was passed to may hold on to it. If the code that it was handed to is a simple function, then the reference may fall out of scope when the function exits. If the code that you handed the callback to is an event handler, though, you might have to think a little more about cleaning up the callback / event handler

DOM Events And Event Handlers

The DOM (Document Object Model – the JavaScript representation of the HTML in your app) is a JavaScript object. Events and other references to your DOM work the same as any other reference. If you have an object handling a DOM event, it has a reference in your app and it won’t be cleaned up by the garbage collector. If you want it cleaned up, you have to remove all references to it – including the DOM reference from the event handler.

Cleaning Up After Yourself

The general rule for cleaning up memory usage in JavaScript is that you have to do it yourself. It’s not quite like C/C++ where you have to allocate and deallocate memory directly. It’s more like Java and C# where you have to release all references to an object before it can be cleaned up by the garbage collector.

You can’t really force garbage collection in JavaScript. Even if you could, you wouldn’t want to. Garbage collection is controlled by the runtime because the runtime knows better than you, about when it should clean things up. Even though you can’t force the garbage collection, you can force a variable to be de-referenced and allow the thing it points to be cleaned up by using the delete keyword in JavaScript: `delete myVar`. This deletes the reference, not the actual object / value it points to. If you delete the final reference, though, garbage collection can take place on the actual object / value.

Cleaning Up In A Backbone App

Backbone is JavaScript so it falls under the same rules. But there are some interesting uses of references in Backbone that you need to be aware of which will help you to know when you need to manually clean up some objects, though.

For example: events. An even handler / callback method works by having a reference between the object that triggers the event and the callback that handles the event. This is one of the easiest places to cause memory leaks in a Backbone app and I discuss it in detail in my Zombies! blog post.

Additionally, my Backbone.Marionette framework that sits on top of Backbone does a lot of cleanup work for you. I provide access to a Region object and various types of views that automatically clean up DOM references, child-view references, event handler references, etc.

Other than being aware of how events work in terms of references, just follow the standard rules for manage memory in JavaScript and you’ll be fine. If you are loading data in to a Backbone collection full of User objects you want that collection to be cleaned up so it’s not using anymore memory, you must remove all references to the collection and the individual objects in it.  Once you remove all references, things will be cleaned up. This is just the standard JavaScript garbage collection rule.

There’s More To It…

Even though these basic rules apply to all of the JavaScript runtime environment, following them might not be enough. There are some additional patterns and practices that can help you prevent too much memory from being used in the first place.

For example, don’t define functions inside of object constructors unless you absolutely have to. Doing this will create a new copy of the function every time you instantiate an object. Instead, attach functions to the object prototype. This will reduce the overall memory footprint of an application, reduce the amount of work that the garbage collector has to do, and generally improve your application performance.

There’s more to it, still. If you’re interested in getting all the detail, check out some of these resources:

Also, be sure to check out my WatchMeCode screencast: JavaScript Zombies – in this episode, I cover some of the most common and basic ways in which memory leaks happen in JavaScript, and show how to overcome these problems.

NewImage

 


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in Backbone, DOM, Javascript, Marionette. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Dom Barker

    JMVC does some really neat things for handling memory leaks

  • http://latentflip.com/blog Anonymous

    Is there an easy way in something like Chrome’s web inspector to check if a particular object has been properly cleaned up? I’m thinking something like:

    - navigate to a view plus model in my backbone app
    - open the web inspector and look at the view and model somewhere
    - navigate to a different view
    - use the web inspector to check the old view and model have been GC’d

    Being able to do that would really help me understand/play with GC to get my head around it better.

    • http://mutedsolutions.com Derick Bailey

      I’m not sure I can directly answer your question, but I ran across this article today and though it might be useful: http://gent.ilcore.com/2011/08/finding-memory-leaks.html

      • Anonymous

         Oh my, this is exactly what I wanted and never knew existed.

    • rdamborsky

      For anyone interested: Heap Profiling in Google Dev Tools: https://developers.google.com/chrome-developer-tools/docs/heap-profiling

  • http://mishareyzlin.com Misha Reyzlin

    I think it is worth mentioning that “you can force a variable to be de-referenced and allow the thing it points to be cleaned up by using the delete keyword in JavaScript: `delete myVar`” will not work with variables declared with `var`. As `delete` works with properties of objects (and in case of non `var` declaration the declared variable is actually a part of global object [`window` in browsers]). 

    • http://mutedsolutions.com Derick Bailey

      right – i always forget about that, for some reason. a “var” will fall out of scope, though, and be cleaned up, when the function exits (assuming no closures on the var). 

      there was an article I read a while back that talked about “delete” great detail, but i can’t seem to find it anymore.

  • Jason

    If this were expanded, do you think it could be of use?
    https://github.com/jstrimpel/emem 

  • Pablo Villoslada Puigcerber

    Hi Derick!

    I dropped you a tweet but seems you didn’t read it. My question is, after removing a Backbone Model from a Backbone Collection, would be enough to call off() in the model so it can be garbage collected?

    Cheers, Pablo.

    • http://mutedsolutions.com Derick Bailey

      Hey Pablo,

      Sorry about that – I did see your tweet and meant to respond, but got lost in other things.

      The short answer is: maybe.

      For any JavaScript object to be garbage collected, all of the it’s references either need to be removed or need to fall out of scope so that the reference doesn’t mean anything because the parent or paren of parent or parent or however far up the chain is no longer referenced.

      Calling .off() on the model will remove any event handler that was set up using .on() for that model. This will remove one set of references. But you may have other references, such as a view instance or any number of other objects holding on to that model. If even a single object or event handler still has a live reference (one that has not fallen out of scope), then the model will not be garbage collected.

      • Pablo Villoslada Puigcerber

        Thanks Derick!

        Your post about Zombie Views is awesome and helped me a lot, but suddenly last week I realized that what I had was some kind of Zombie Models cause I wasn’t unbinding all the events.

        Cheers, Pablo.