Утечка памяти jQuery с удалением DOM

Вот простейшая веб-страница, которая утечки памяти в IE8 с помощью jQuery (я обнаруживаю утечки памяти, наблюдая за использованием памяти моего процесса iexplore.exe со временем в диспетчере задач Windows):

  Test Page     function resetContent() { $("#content div").remove(); for(var i=0; i<10000; i++) { $("#content").append("
Hello World!
"); } setTimeout(resetTable, 2000); } $(resetContent);

По-видимому, даже при вызове функции jQuery.remove() я все еще испытываю некоторую утечку памяти. Я могу написать свою собственную функцию удаления, которая не испытывает утечки памяти следующим образом:

 $.fn.removeWithoutLeaking = function() { this.each(function(i,e){ if( e.parentNode ) e.parentNode.removeChild(e); }); }; 

Это прекрасно работает и не утечки памяти. Итак, почему происходит утечка памяти jQuery? Я создал другую функцию удаления, основанную на jQuery.remove() и это действительно вызывает утечку:

 $.fn.removeWithLeakage = function() { this.each(function(i,e) { $("*", e).add([e]).each(function(){ $.event.remove(this); $.removeData(this); }); if (e.parentNode) e.parentNode.removeChild(e); }); }; 

Интересно, что утечка памяти, по-видимому, вызвана каждым вызовом, который включает jQuery для предотвращения утечки памяти из событий и данных, связанных с удаляемыми элементами DOM. Когда я removeWithoutLeaking функцию removeWithoutLeaking моя память остается постоянной с течением времени, но когда я вызываю removeWithLeakage то она просто продолжает расти.

Мой вопрос: как насчет этого вызова?

 $("*", e).add([e]).each(function(){ $.event.remove(this); $.removeData(this); }); 

может вызвать утечку памяти?

EDIT: Исправлена ​​опечатка в коде, которая при повторном тестировании не оказывала влияния на результаты.

ДАЛЬНЕЙШЕЕ ИЗМЕНИТЬ: я написал отчет об ошибке с проектом jQuery, так как это похоже на ошибку jQuery: http://dev.jquery.com/ticket/5285

    6 Solutions collect form web for “Утечка памяти jQuery с удалением DOM”

    Я думал, что Дэвид может быть на что-то с предполагаемой утечкой removeChild, но я не могу воспроизвести его в IE8 … это может случиться в более ранних браузерах, но это не то, что у нас есть. Если вручную удалитьChild divs нет утечки; если я outerHTML= '' jQuery, чтобы использовать outerHTML= '' (или перемещать в корзину, а затем bin.innerHTML) вместо removeChild все еще существует утечка.

    В процессе устранения я начал взламывать биты remove в jQuery. строка 1244 в 1.3.2:

     //jQuery.event.remove(this); jQuery.removeData(this); 

    Комментируя эту строку, не было никакой утечки.

    Итак, давайте посмотрим на event.remove, он вызывает data('events') чтобы увидеть, есть ли какие-либо события, связанные с элементом. Что делают data ?

     // Compute a unique ID for the element if ( !id ) id = elem[ expando ] = ++uuid; 

    Ой. Таким образом, он добавляет один из свойств hack-to-data-lookup для jQuery для каждого элемента, к которому он даже пытается читать данные, включая каждый отдельный потомок элемента, который вы удаляете! Как глупо. Я могу закоротить это, поставив эту строку непосредственно перед ней:

     // Don't create ID/lookup if we're only reading non-present data if (!id && data===undefined) return undefined; 

    который, как представляется, устраняет утечку для этого случая в IE8. Не могу гарантировать, что это не сломает что-то еще в лабиринте jQuery, но логически это имеет смысл.

    Насколько я могу решить, утечка – это просто объект jQuery.cache (который является хранилищем данных, а не действительно кешем как таковым) становится все больше и больше, поскольку новый ключ добавляется для каждого удаленного элемента. Хотя removeData должен удалять эти записи кэша ОК, IE не восстанавливает пространство при delete ключа из объекта.

    (В любом случае, это пример такого поведения jQuery, которое я не ценю. Он слишком много под капотом, что должно быть просто простой операцией … некоторые из которых довольно сомнительные. вещь с расширением и то, что jQuery делает для innerHTML через регулярное выражение, чтобы исключить, что отображение в качестве атрибута в IE просто сломано и уродливо. И привычка делать геттер и сеттер одной и той же функцией запутанна и, здесь, приводит к ошибке. )

    [Странно, оставив testtest в течение продолжительного периода времени, изредка изредка выдавал полностью ложные ошибки в jquery.js до того, как память на самом деле закончилась … было что-то вроде «неожиданной команды», и я заметил, что «nodeName имеет значение null или нет объект ‘в строке 667, который, насколько я могу видеть, даже не должен запускаться, не говоря уже о том, что там есть проверка, что nodeName имеет значение null! IE не дает мне большой уверенности здесь …]

    Кажется, исправлено в jQuery 1.5 (версия 23 февраля). Я столкнулся с той же проблемой с 1.4.2 и исправил ее сначала с удалением dom, как описано выше, а затем, попробовав новую версию.

    Удаление элемента является неотъемлемой проблемой DOM. Что останется с нами. То же самое.

     jQuery.fn.flush = function() ///  /// $().flush() re-makes the current element stack inside $() /// thus flushing-out the non-referenced elements /// left inside after numerous remove's, append's etc ... ///  { return jQuery(this.context).find(this.selector); } 

    Вместо взлома jQ я использую это расширение. Особенно на страницах с большим количеством удалений () и клонов ():

     $exact = $("whatever").append("complex html").remove().flush().clone(); 

    А также следующий помогает:

     // remove all event bindings , // and the jQ data made for jQ event handling jQuery.unbindall = function () { jQuery('*').unbind(); } // $(document).unload(function() { jQuery.unbindall(); }); 

    См. Дорожную карту jQuery 1.4 по адресу http://docs.jquery.com/JQuery_1.4_Roadmap . В частности, раздел «Использовать .outerHTML для очистки после .remove ()» имеет дело с проблемами утечки памяти, возникающими в IE из-за вызываемой функции удаления.

    Возможно, ваши проблемы будут решены в следующем выпуске.

    По-прежнему ли он течет, если вы вызываете empty а не remove ?

     $("#content").empty(); 

    JQuery 1.4.1 имеет следующее:

      cleanData: function (elems) { for (var i = 0, elem, id; (elem = elems[i]) != null; i++) { jQuery.event.remove(elem); jQuery.removeData(elem); } } 

    Вот что мне пришлось изменить, чтобы устранить проблему утечки:

      cleanData: function (elems) { for (var i = 0, elem, id; (elem = elems[i]) != null; i++) { jQuery.event.remove(elem); jQuery.removeData(elem); jQuery.purge(elem); } } 

    добавленная функция:

      purge: function (d) { var a = d.childNodes; if (a) { var remove = false; while (!remove) { var l = a.length; for (i = 0; i < l; i += 1) { var child = a[i]; if (child.childNodes.length == 0) { jQuery.event.remove(child); d.removeChild(child); remove = true; break; } else { jQuery.purge(child); } } if (remove) { remove = false; } else { break; } } } }, 
    Interesting Posts

    Поиск индексов множественных / совпадающих совпадающих подстрок

    Как сопоставить настраиваемый протокол с приложением на Mac?

    Есть ли способ отключить этот анонимный удар барабана и приветствовать шум для Ubuntu

    Многопоточный рендеринг на OpenGL

    Дизайн Android EditText, чтобы отобразить сообщение об ошибке, как описано в Google

    Проблема с отображением в «новых» программах Microsoft в Windows 7

    ssl.SSLError: версия протокола предупреждения tlsv1

    Как выбрать адреса и сервер DNSMasq для PPTP VPN-клиента (в DD-WRT)?

    Почему получение Google Directions для Android с использованием данных KML больше не работает?

    Как отключить «Open File Security Warning», когда я хочу запустить загруженные исполняемые файлы?

    Преобразование внешнего жесткого диска в NTFS

    Как избежать апострофа (‘) в MySql?

    Как запустить процесс как режим администратора в C #

    Как запустить хранимые процедуры в Entity Framework Core?

    Создать указатель на двумерный массив

    Давайте будем гением компьютера.