2012-02-16 2 views
14

Я вижу, что обработчики событий, зарегистрированные через .on(), хранятся в $.cache. Я также вижу, что обработчики событий также хранятся в $(elem).data().

Объекты, хранящиеся в $.cache, относятся к узлам DOM, на которых зарегистрированы события. Это приводит к утечке памяти при отсоединении узлов DOM, и это делает обязательными .off().

У меня есть ситуация, когда я не знаю, когда узел DOM (к которому я привязал обработчик события) отсоединяется. Хотя я могу хранить ссылку на этот узел DOM в своем коде и вызывать .off() для очистки, это не кажется приятным, потому что не просто знать, когда удаляется узел DOM.

Каков наилучший способ для этого?

ответ

16

«Каков наилучший способ для этого?»

Если вы собираетесь использовать JQuery, вы должны использовать его API для удаления элементов, и вы должны использовать правильные методы, в противном случае, как вы заявили, вы будете иметь утечку памяти.

Если вы не знаете, когда удаляется узел DOM, и если он вызывает утечку, я бы предположил, что это означает, что вы используете другую библиотеку вместе с jQuery. Именно по этой причине это не очень хорошая идея.

Вы должны убедиться, что jQuery удалены из любого элемента, затронутого jQuery. Также есть некоторые данные, хранящиеся в $.cache, которые вы явно не задали. Это означает, что все элементы должны быть удалены с помощью jQuery, а не только те, что вы думаете, что могут иметь данные.


"Какова цель $.cache в JQuery?"

Связать обработчики и другие данные с элементами. Связь между данными и элементами в основном представляет собой серийный номер, хранящийся в свойстве expando элемента.

Если вы удалите элемент без jQuery, связанные данные в $.cache останутся без работы.

Целью этого подхода было предотвращение потенциальных утечек. К сожалению, это потенциально создает более серьезные утечки.

+0

1. Если отношение между элементом и обработчиками поддерживается через серийный номер (и если обработчик не относится к элементу), я не вижу причин, по которым записи .cache должны приводить к памяти протечь. По какой-то причине я не знаю, насколько это оправдано, запись в кэш относится к элементу. Мне любопытно узнать, почему требуется ссылка на элемент. 2. Мне не известны случаи, когда expando элемента не может напрямую ссылаться на объекты (обработчики). Если expando может содержать ссылки, я не вижу необходимости в параллельной структуре, например .cache, для хранения ссылок. – user968903

+0

@ user968903: 1. Они приводят к утечкам, если вы не используете методы jQuery, которые удаляют связанную запись '.cache' при удалении элемента. Серийный номер является единственным соединением между ними, поэтому, если элемент с последовательным '123' удален, но jQuery не удаляет запись' 123' в '$ .cache', то эта запись теперь ссылается на данные, которые больше не имеет соответствующий элемент и никогда не будет очищен. Обоснованием были потенциальные утечки памяти, которые существуют прежде всего в IE6 и, возможно, в IE7. Теперь, когда эти браузеры почти исчезли, я не знаю, хорошо ли этот подход. –

+0

@ user968903: 2. Я думаю, что современные браузеры обычно очищают элементы при удалении, поэтому, вероятно, это уже не проблема. Я считаю, что в первую очередь были проблемы с IE6/7. Я думаю, что все еще могут быть потенциальные утечки памяти в отношении замыканий, когда у элемента есть обработчик, который имеет в своей переменной область круговую ссылку на себя, но я не уверен, что это проблема сегодня или нет. Я посмотрю, что я могу найти. –

5

Я столкнулся с аналогичной ситуацией, когда нокаут используется для добавления и удаления домиков из документа. Однако jquery используется для подключения прослушивателей событий к этим деревьям. Когда нокаут удаляет элементы dom из документа, слушатели не отключаются, поэтому дерево доминирования никогда не имеет права на сбор мусора. Мы добавили функцию очистки, которая тратит через jquery $ .cache каждый раз при изменении хеша и находит даже обработчиков, которые привязаны к деревьям, которые не находятся в документе. Затем он отталкивает слушателей, тем самым делая дерево домиков подходящим для сбора мусора и фиксируя большую часть утечек, которые мы наблюдаем, то есть круглые поездки вокруг приложения, используемого для утечки 13 МБ, теперь он протекает только с 3 МБ с этими изменениями на месте.

for (var i in $.cache) { 
      if ($.cache.hasOwnProperty(i)) { 

       if ($.cache[i].handle && $.cache[i].handle.elem && document !== $.cache[i].handle.elem && !jQuery.contains(document, $.cache[i].handle.elem)) { 
        //we have an event handler pointing to a detached dom element! 
        //this is a memory leak as this detached dom element cannot be garbage collected until 
        //all references to it are removed. So lets delete the event handler to get memory back! 
        var orphan = $($.cache[i].handle.elem); 
        $('body').append(orphan); 
        orphan.off(); 
        orphan.remove(); 
        orphan = null; 
       } 
      } 
     } 
+1

Похоже, что это результат ошибки в нокауте 3.0.0. Когда я обновился до 3.1.0, утечка памяти исчезла без необходимости в указанном выше коде! – Troup

Смежные вопросы