1

I'm struggling with getting the concept of memory management with single page applications. This is my code:

var FilterModel = Backbone.Model.extend({});
    var taskView = Backbone.View.extend({
        template: _.template('<h1><%= title %></h1>'),
        initialize: function(){
            this.render();
            this.listenTo(this.model, 'destroy', this.remove);
            console.log(this.model)
        },
        render: function(){

            this.$el.html(this.template(this.model.toJSON()));
            return this;
        },
        events:{
            'click h1': 'removeView'

        },
        removeView: function(){
            this.model.destroy();
            console.log('removed');

        }
    });
    var filterModel = new FilterModel({title: 'Test'});
    var taskview = new taskView({model:filterModel});

// I make heap snapshot before and after the change!
    setTimeout(function(){
        $("h1").click()}, 3000
    )
    $('body').append(taskview.$el);

I was told by numerous articles that using "remove" and "destroy" would clean up any memory leaks when removing the DOM tree.

But Chrome profile utility tells otherwise. I get detached DOM elements no matter what I do.

UPDATE!!! After trying a few things in the responses I still get this in Google Chrome: Here is jsfiddle: http://jsfiddle.net/HUVHX/ enter image description here

Janck
  • 55
  • 7

2 Answers2

1

So Janck, you can fin your answer here: Backbone remove view and DOM nodes

The problems is that you have to do more than just remove you model and view.

You need to properly destroy all of the events and other bindings that are hanging around when you try to close your views.

I don't know if you know about Marionette.js (Backbone.Marionette), but it's a great extension to Backbone to handle this Zombie Views and to create robust JS applications.

You can read some articles about this as well, they were pointed in the Stackoverflow link that I posted.

http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/

http://lostechies.com/derickbailey/2012/03/19/backbone-js-and-javascript-garbage-collection/

But the logic is this: If a View is listening a model, then the contrary also occurs, so you'll always get a instance of your View in your DOM.

Community
  • 1
  • 1
Leonardo Barbosa
  • 1,258
  • 8
  • 13
  • Thank you for your response. I have heard of Marionette but I'm not sure how much effort it would take to redesign my app. I can see that there are no quick solutions and that I must take a different approach. Could you advise me on the code I've posted in my original question? I've also tried to use "stopListening()" on the model and view as well but it didn't do the trick. – Janck Apr 16 '14 at 13:32
1

taskview is still holding a strong reference to this.el, although it is not connected to the dom. This is not a memory leak because taskview is held strongly also by it's variable

To test my assumption just add:

removeView: function(){
  this.model.destroy();
  this.el = undefined;
  this.$el = undefined;
}

Another approach is to undef taskview var

EDIT:

When I change: "click h1" : "removeView" To "click": "removeView" it solves the detached dom node leak.

I suspect this has something to do with jquery selector caching.

You can see in backbone code, the difference is in calling jquery on function with a selector:

if (selector === '') {
   this.$el.on(eventName, method);
} else {
  this.$el.on(eventName, selector, method);
}

I tried to trace the cache deep into jquery code, with no luck.

ekeren
  • 3,408
  • 3
  • 35
  • 55
  • I've tried this and still get the same result. (I've updated my original post with a screenshot) – Janck Apr 17 '14 at 06:51
  • 1
    @Janck - can you post this code on a jsfiddle, so we can take a deeper look – ekeren Apr 17 '14 at 11:26
  • this is very interesting, I tried turning off jQuery cache but got the same result, also I taught that all jQuery cached elements would be described by dev tools as jQuery sizzle. Anyhow...I finally made it work, I will be posting the code soon but I think it also had to do with the browser cache. Now I'm rebuilding my code with marionette as it seems to be the best option. Thank you for your input – Janck Apr 20 '14 at 09:38
  • 1
    @Janck IMO, Marionette is indeed the best option. I don't think it will solve this kind of memory leak... but it will save you from writing a lot of boilerplate code, good luck. Were you able to find the actual leak? – ekeren Apr 20 '14 at 09:55
  • Yes, this.el was still holding a reference but somehow I didn't manage to make it work the first time. I'm looking at marionette atm and already see that there are many good "forced" practices. Incorporated close function and defining a region for view seem to be great for avoiding memory leaks. – Janck Apr 21 '14 at 12:12
  • what do you mean by not going to solve this kind of memory leak? – Janck Apr 21 '14 at 13:59
  • 1
    First.. I am also using marionette for every backbone project I am doing, It is great. As far as I can see, This is not a real memory leak it is some caching mechanism that I can't really trace... – ekeren Apr 22 '14 at 09:32
  • I'm dealing with the whole issue of memory leaks with marionette and as I see in dev tools time line and event listeners are successfully removed. Should I also see immediate fall in number of node elements when I remove a view? – Janck Apr 22 '14 at 10:00
  • AFAIK, The removal of nodes will happen only when the GC is invoked, so you will not see them on remove. When working with marionette I advise to forget about memory leaks when you develop, you should clear time in your development cycle for memory profiling to make sure all is working as it should. from my experience it will. – ekeren Apr 22 '14 at 10:05