Почему эта утечка в Internet Explorer 8? - PullRequest
11 голосов
/ 05 февраля 2011

Почему возникает утечка следующего кода?

for (var i = 0; i < 100; i++) {
    var item = {};
    item.elem = document.createElement('div');
    document.body.appendChild(item.elem);
    item.addEvent = function(name,listener) {
        var self = this;
        var wrappedListener = function() {
            return listener.apply(self,arguments);
        }
        //Uh-oh creating a circular reference here!
        //The wrappedListener has a closure on self and therefore on item.elem.
        addEvent(this.elem,name,wrappedListener);
        return wrappedListener;
    }
    var wrap = item.addEvent('eventName',listen);

    //Now remove the eventHandler - this should free up the circular reference.
    removeEvent(item.elem, 'eventName', wrap);
    if (item.elem.parentNode) {
        item.elem.parentNode.removeChild(item.elem);
    }
    //item.elem = null; //With this also un-commented, the leak disappears.
    //The fact that I have to null item.elem tells me that something is holding
    //a reference to item, and therefore elem. Setting elem to null fixes the
    //problem, but since I am removing the event handler, I don't think this
    //should be required.
}

Примечание: addEvent и removeEvent предназначены только для того, чтобы абстрагировать attachEvent / addEventListener различия между Internet Explorer и другими браузерами.

Я создал jsFiddle проект, который демонстрирует проблему.Просто запустите Internet Explorer 8 и смотрите его в диспетчере задач или в Process Explorer.Кроме того, вы увидите определение addEvent и removeEvent.

http://jsfiddle.net/rJ8x5/34/

РЕДАКТИРОВАТЬ: Ну, я пришел к следующему решению.Это не красиво, но это работает!http://jsfiddle.net/rJ8x5/43/

var item = {};
item.elem = document.createElement('div');
document.body.appendChild(item.elem);
item.addEvent = function(name,listener) {
    var wrappedListener = function() {
        //Access the scope through the callee properties.
        return listener.apply( arguments.callee.scope, arguments);
    }
    addEvent(this.elem,name,wrappedListener);
    //Save the scope not as a closure, but as a property on the handler.
    wrappedListener.scope = this
    return wrappedListener;
}
var wrap = item.addEvent('eventName',listen);
removeEvent(item.elem, 'eventName', wrap);
//Force the circular reference to GO AWAY.
wrap.scope = null
if (item.elem.parentNode) {
    item.elem.parentNode.removeChild(item.elem);
}
//item.elem = null; //No longer needed.

Ответы [ 2 ]

5 голосов
/ 05 февраля 2011

Проблема в событиях (как почти всегда в Internet Explorer, кстати).

Посмотрите на http://jsfiddle.net/rJ8x5/39/ и обратите внимание, как хорошо собирается мусор.

При создании событий вы создаете циклические ссылки. Подробнее об этом читайте в Циркулярные ссылки на объекты DOM на странице HTML вызывают утечку памяти .

1 голос
/ 07 июня 2012

Код протекает из-за неправильного вызова attachEvent - документация Microsoft настаивает на том, чтобы имя события было стандартным событием DHTML.

Если изменить 'eventName' на 'click', он не протечет.

Более надежное решение состояло бы в том, чтобы изменить код, присоединяющий ваше событие, к проверке 'on'+eventname in domElement и отказаться от присоединения события, если это ложно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...