错误代码分析

内存泄露及解决方案

阻止基类进行清理

在子类的清理程序中,忽略了调用基类的清理程序。

Ext.define('Foo.bar.CustomButton', {
    extend: 'Ext.button.Button',
    onDestroy: function () {
        // do some cleanup
    }
});

解决方案:确保调用 callParent() 方法。

未移除DOM事件监听

DOM元素添加了事件处理,通过innerHTML改变了元素。但是元素的事件处理驻留再内存中。

Ext.fly(someElement).on('click', doSomething);
someElement.parentNode.innerHTML = '';

解决方案:保留重要元素的引用,如果不需要该元素的时候调用其 destroy() 方法。

一直引用对象

创建了一个类的实例,并且使用了大量的内存。该实例被销毁,但是存在的对象上保留了对该实例的引用。

Ext.define('MyClass', {
    constructor: function() {
        this.foo = new SomeLargeObject();
    },
    destroy: function() {
        this.foo.destroy();
    }
});

this.o = new MyClass();
o.destroy();

// `this` still has a reference to `o` 
// and `o` has a reference to `foo`.

解决方案:设置引用为 null,确保内存被释放。在这个示例中,在清理方法内设置this.foo = null, 调用o.destroy()后,设置 this.o = null

闭包引用

这种情况更微妙(subtle),与上述的情况相似。闭包包含对一个大对象的引用,当闭包还在被引用的时候,不能释放大对象占用的内存。

function runAsync(val) {
    var o = new SomeLargeObject();
    var x = 42;

    // other things

    return function() {
         // o is in closure scope but not needed
        return x; 
    }
}

var f = runAsync(1);

因为大对象在作用域外定义,在内部函数中并未使用,这类情况很容易被忽略,但是对内存影响很大。

解决方案:在该函数体外定义函数,然后使用 Ext.Function.bind()方法,或者标准 JavaScript 函数bind 创建安全的闭包。

function fn (x) {
    return x;
}

function runAsync(val) {
    var o = new SomeLargeObject();
    var x = 42;

    // other things

    // o is not captured
    return Ext.Function.bind(fn, null, [x]); 
}

var f = runAsync(1);

持续创建对象实例

创建对象要付出一定的代价(例如:创建DOM元素)。如果创建了但是没销毁就会导致内存泄露。

{
    xtype: 'treepanel',
    listeners: {
        itemclick: function(view, record, item, index, e) {

            // Always creating and rendering a new menu
            new Ext.menu.Menu({
                items: [record.get('name')]
            }).showAt(e.getXY());
        }
    }
}

解决方案:保留对menu的引用,不再需要menu时调用其destroy()方法进行销毁。

清理缓存项

切记删除对一个对象的所有引用。只设置当前引用为 null还不够。如果一些全局的单例缓存还在引用该对象,那么其引用在应用的生命周期内将一直存在。

var o = new SomeLargeObject();
someCache.register(o);

// Destroy and null the reference. someCache still has a reference
o.destroy();
o = null;

解决方案:确保从所有缓存中移除对象后再调用其destroy()方法。

results matching ""

    No results matching ""