Page 1 of 2 12 LastLast
Results 1 to 10 of 15

Thread: Blog post: Tips for finding memory leaks in Sencha applications

  1. #1
    Sencha Premium User mankz's Avatar
    Join Date
    Nov 2007
    Location
    Stockholm, Sweden
    Posts
    3,153

    Default Blog post: Tips for finding memory leaks in Sencha applications

    Just did a blog post about finding memory leaks, thought it might be useful for peers in the community. Feedback would be very much appreciated.

    http://www.bryntum.com/blog/finding-...-applications/

  2. #2
    Sencha Premium User Tim Toady's Avatar
    Join Date
    Feb 2010
    Location
    Pennsylvania
    Posts
    605

    Default

    Great post. Will definitely reference it in the future. Memory leaks can sometimes be difficult to track down.

  3. #3
    Sencha Premium User
    Join Date
    Nov 2010
    Location
    Chicago
    Posts
    2,425

    Default

    "A memory leak appears when a resource thats no longer used by any part of your application still occupies memory which will never be released."

    I believe it's not enough to destroy the not-needed object to avoid a memory leak. Any pointers to the destroyed object should be assigned a null value as well.

    See this example... I think the Window class should null the keyMap pointer to avoid a memory leak. Otherwise, when the window object is destroyed, it will not be garbage collected because it still points to the destroyed keyMap object.

    Feel free to correct my comment if there's a fault in my reasoning.
    Code:
    Ext.define('Ext.window.Window', {
        extend: 'Ext.panel.Panel',
        ...
        beforeDestroy: function() {
            var me = this;
            if (me.rendered) {
                ...
                Ext.destroy(
                    me.keyMap
                );
                me.keyMap = null; // <-- Add this line
            }
            me.callParent();
        },
        ...
    *******************************************
    Ext.define('Ext.panel.Panel', {
        ...
        getKeyMap: function() {
            return this.keyMap || (this.keyMap = new Ext.util.KeyMap(Ext.apply({
                target: this.el
            }, this.keys)));
        },
        ...

  4. #4
    Sencha Premium User mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    40,451

    Default

    Why did you null out keyMap property in Ext.window.Window when it's set in Ext.panel.Panel? Shouldn't it be added to Ext.panel.Panel or else Ext.panel.Panel (and any other subclass like Ext.form.Panel) still have the leak.

    And yes, if an array/object/node/instance is not cleaned up somewhere, it's a leak. So if the keyMap property is not nullified (or the like) then it is a memory leak.

    Memory leaks are incredibly easy to make, one of the downsides to JavaScript.
    Mitchell Simoens @LikelyMitch
    Modus Create, Senior Fullstack Engineer
    ________________
    Modus Create is based on the model of an open source team. We’re a remote, global team of experts in our field. To find out more about the work we do, head over to our website.

    Check out my GitHub:
    https://github.com/mitchellsimoens

  5. #5
    Sencha Premium User
    Join Date
    Nov 2010
    Location
    Chicago
    Posts
    2,425

    Default

    Quote Originally Posted by mitchellsimoens View Post
    Why did you null out keyMap property in Ext.window.Window when it's set in Ext.panel.Panel? Shouldn't it be added to Ext.panel.Panel or else Ext.panel.Panel (and any other subclass like Ext.form.Panel) still have the leak.
    Good point!

  6. #6
    Sencha Premium User mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    40,451

    Default

    Something like this is a memory leak also (which I see in code all the time, I use this method too):

    Code:
    Ext.define('MyClass', {
        extend : 'Ext.container.Container',
        xtype  : 'myclass',
    
        config : {
            mySomething : {
                xclass : 'MySomething'
            }
        },
    
        applyMySomething : function(something) {
            if (something && !something.isComponent) {
                something = Ext.create(something);
            }
    
            return something;
        },
    
        updateMySomething : function(something, oldSomething) {
            if (something) {
                if (this.isConfiguring) {
                    var items = this.items;
                    
                    if (!items) {
                        items = this.items = [];
                    }
                    
                    items.push(something);
                } else {
                    this.suspendLayouts();
        
                    if (oldSomething) {
                        this.remove(oldSomething);
                    }
        
                    this.add(something);
        
                    this.resumeLayouts(true);
                }
            }
        }
    });
    Now when you create an instance and destroy it, the mySomething property still resolves to the instance created in the applyMySomething. So you have to take care of it:

    Code:
    Ext.define('MyClass2', {
        extend : 'Ext.container.Container',
        xtype  : 'myclass2',
    
        config : {
            mySomething : {
                xclass : 'Ext.Component'
            }
        },
        
        destroy : function() {
            this.setMySomething(null);
            
            this.callParent();
        },
    
        applyMySomething : function(something) {
            if (something && !something.isComponent) {
                something = Ext.create(something);
            }
    
            return something;
        },
    
        updateMySomething : function(something, oldSomething) {
            if (something) {
                if (this.isConfiguring) {
                    var items = this.items;
                    
                    if (!items) {
                        items = this.items = [];
                    }
                    
                    items.push(something);
                } else {
                    this.suspendLayouts();
        
                    if (oldSomething) {
                        this.remove(oldSomething);
                    }
        
                    this.add(something);
        
                    this.resumeLayouts(true);
                }
            }
        }
    });
    Or, if you want to clear all items in the class' config object, use the configurator:

    Code:
    Ext.define('MyClass3', {
        extend : 'Ext.container.Container',
        xtype  : 'myclass3',
    
        config : {
            mySomething : {
                xclass : 'Ext.Component'
            }
        },
        
        destroy : function() {
            var configurator = this.getConfigurator(),
                configs      = configurator.configs,
                name;
            
            for (name in configs) {
                if (configs.hasOwnProperty(name)) {
                	configs[name].setter.call(this, null);
                }
            }
            
            this.callParent();
        },
    
        applyMySomething : function(something) {
            if (something && !something.isComponent) {
                something = Ext.create(something);
            }
    
            return something;
        },
    
        updateMySomething : function(something, oldSomething) {
            if (something) {
                if (this.isConfiguring) {
                    var items = this.items;
                    
                    if (!items) {
                        items = this.items = [];
                    }
                    
                    items.push(something);
                } else {
                    this.suspendLayouts();
        
                    if (oldSomething) {
                        this.remove(oldSomething);
                    }
        
                    this.add(something);
        
                    this.resumeLayouts(true);
                }
            }
        }
    });
    Fiddle of all 3:

    Mitchell Simoens @LikelyMitch
    Modus Create, Senior Fullstack Engineer
    ________________
    Modus Create is based on the model of an open source team. We’re a remote, global team of experts in our field. To find out more about the work we do, head over to our website.

    Check out my GitHub:
    https://github.com/mitchellsimoens

  7. #7
    Sencha Premium User
    Join Date
    Nov 2010
    Location
    Chicago
    Posts
    2,425

    Default

    Quote Originally Posted by mitchellsimoens View Post
    Now when you create an instance and destroy it, the mySomething property still resolves to the instance created in the applyMySomething. So you have to take care of it:
    Why the class config machinery doesn't do this for me?

    All configs should be null'd when the instance is destroyed.

    Code:
    Ext.define('Test', {
        config: {
            msg: {text: 'Hi there!'}
        },
    
    
        constructor: function(config) {
            this.initConfig(config);
        }
    });
    
    
    var test = new Test();
    
    
    test.destroy();
    
    
    test.getMsg().text // Should be null, but it's not.

  8. #8
    Sencha Premium User mankz's Avatar
    Join Date
    Nov 2007
    Location
    Stockholm, Sweden
    Posts
    3,153

    Default

    Les, if no reference is found to any instance of your Window class or Test class, then it shouldn't matter how the object looks internally. At least that's my understanding

  9. #9
    Sencha Premium User mitchellsimoens's Avatar
    Join Date
    Mar 2007
    Location
    Gainesville, FL
    Posts
    40,451

    Default

    Quote Originally Posted by mankz View Post
    Les, if no reference is found to any instance of your Window class or Test class, then it shouldn't matter how the object looks internally. At least that's my understanding
    I don't think it's that simple or else why nullify the items collection and other things? For example, in Ext.Component#destroy, there is this:

    Code:
                    me.data = me.el = me.frameBody = me.rendered = me.afterRenderEvents = null;
                    me.tpl = me.renderTpl = me.renderData = null;
                    me.focusableContainer = me.container = me.scrollable = null;
    me.data for example, then that's unneeded code or just for good measure in case the object/array is referenced somewhere else?
    Mitchell Simoens @LikelyMitch
    Modus Create, Senior Fullstack Engineer
    ________________
    Modus Create is based on the model of an open source team. We’re a remote, global team of experts in our field. To find out more about the work we do, head over to our website.

    Check out my GitHub:
    https://github.com/mitchellsimoens

  10. #10
    Sencha Premium User mankz's Avatar
    Join Date
    Nov 2007
    Location
    Stockholm, Sweden
    Posts
    3,153

    Default

    I think it would matter if those properties are not "internal" but shared with other objects, then of course getting rid of your reference will be key. Also guessing the GC behavior could vary from browser to browser so it may be to please IE etc. I'll run a few tests in Chrome tomorrow.

Page 1 of 2 12 LastLast

Similar Threads

  1. Blog post on testing Sencha Touch applications
    By mankz in forum Sencha Touch 2.x: Examples and Showcases
    Replies: 0
    Last Post: 14 Feb 2013, 3:01 AM
  2. Blog post on Sencha Animator
    By infield in forum Sencha Animator Help & Discussion
    Replies: 2
    Last Post: 23 Jun 2011, 4:23 PM
  3. Debugging best practices for finding memory leaks and performance issues
    By brookd in forum Ext 3.x: Help & Discussion
    Replies: 0
    Last Post: 1 Jan 2010, 4:59 PM
  4. Off Topic: Finding Memory Leaks in IE?
    By cluettr in forum Ext 1.x: Help & Discussion
    Replies: 0
    Last Post: 22 Sep 2007, 10:28 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •