Сборщик мусора в JavaScript
Ребята, просветите пожалуйста! Если я создал некий элемент, добавил его в DOM, повесил на него слушателя события, а затем удалил этот элемент из DOM вообще, то что будет со слушателем события? Удаляется ли он вместе с элементом сборщиком мусора или продолжает висеть в памяти?
|
Может вопрос сформулирован неверно?
Или ответ настолько очевиден, что каждый прочитавший, ухмыльнувшись встает и идет кормить рыбок:)
|
ИМХО, получить однозначный ответ на этот вопрос нелегко.
мне кажется все зависит от конкретного браузера, и реализации интепретатора в нем. по хорошему делу, должен убиратся, если конечно не учтаивать замыкания, и прочие изыски, которые однозначно должны оставатся в памяти |
И на этом спасибо!
И на этом спасибо!
|
и на том, пожалуйста)
|
Интересная тема, кстати. Надо бы ее развить.
Если верить этому, то в осле циклические связи между элементами и жскрипт-объектами (в т.ч. функциями) мемори-менеджерами (их там два) не резруливаются, по той причине, что за очистку элементов отвечает один, а за очистку жскриптовых объектов другой, договориться друг с другом они не умеют, и висят в памяти элементы со своими эвент-хэндлерами аж пока жив процесс осла. Во избежание этого во многих джаваскрипт-фрэймворках все аттачи эвент-хэндлеров (и другие связи с дом-объектами) кэшируются, чтобы на момент анлоада странички их очищать. Теперь вопрос: почему эти связи некоторыми товарищами (напр. в Ext) кэшируются и чистятся даже для неослов? |
За Осла судить не берусь, а вот есть у меня один "скриптец" которой я активно юзаю в "3-й лисе".
Я несколько раз специально наблюдал: в процессе работы этого скрипта у меня в течение часа создавалось/убивалось несколько сот объектов с кучей подписок на различные события. При этом объем памяти используемый "лисой" практически не изменялся. Я не уверен насколько это объективно показывает работу "мусорщика"? Есть какие-нибудь плагины/утилиты которые позволяют все это точно оценивать? |
ну, если вас так интересует этот вопрос, то составьте сркипт, с созданием больших объектов(чтоб утечка памяти на глаз была заметна), слушателячми и прочим, и последующим удалением
выложите его тут, пускай в разных протестят, и оформят здесь результаты. а мне влом писать скрипт, я пошел спать. всем спокойной ночи |
Вот такой код для тестирования пойдет:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <title>Test</title> </head> <body> <form action="#" id="test"></form> <script type="text/javascript"> <!--//--><![CDATA[//><!-- var p, d, f, a, ie, n, i; p = 50; // Set period of modifying d = document; f = d.getElementById("test"); a = []; ie = /msie/i.test(navigator.userAgent); n = 0; window.setInterval(doInput, p); function doInput() { i = a.length; if (!i || Math.random() < 0.5) { a[i] = d.createElement("input"); a[i].setAttribute("value", n++); if (ie) { a[i].attachEvent('onclick', e1); a[i].attachEvent('onmousedown', e2); a[i].attachEvent('onmouseup', e3); } else { a[i].addEventListener("click", e1, false); a[i].addEventListener("mousedown", e2, false); a[i].addEventListener("mouseup", e3, false); } f.appendChild(a[i]); } else { f.removeChild(a.shift()); } } function e1() { //alert("Event 1"); } function e2() { alert("Event 2"); } function e3() { alert("Event 3"); } //--><!]]> </script> </body></html> Вот только хотелось бы понять методику для тестирования - что надо проверять окромя "съеденной" браузером памяти? Или "измеренной памяти" достаточно для объективных выводов? |
И что этим кодом можно увидеть? Скачки в несколько килобайт используемой памяти, связаны с работой сборщика мусора. Не в одном браузере утечек памяти не наблюдается.
Вот во время написания фреймворка, я столкнулся с проблемой: при удалении узла через removeChild, в памяти остаются все дочерние узлы, на которые где-либо хранятся ссылки: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script type="text/javascript"> window.onload = function() { // Test 1 var div = document.getElementById('test1'); document.body.removeChild(document.getElementById('conteiner1')); alert(div.id); // Test 2 var div = document.getElementById('test2'), cont = document.getElementById('conteiner2'); while(cont.firstChild) cont.removeChild(cont.firstChild); document.body.removeChild(cont); alert(div.id); // Test 3 document.body.removeChild(document.getElementById('conteiner3')); alert(document.getElementById('test3')); }; </script> </head> <body> <div id="conteiner1"> <div id="test1">Test</div> </div> <div id="conteiner2"> <div id="test2">Test</div> </div> <div id="conteiner3"> <div id="test3">Test</div> </div> </body> </html> Это проблема стала еще более существенной из-за использования кэша по идентификаторам. Решить смог только удалением кэша после операций, связанных с удалением узлов и изменением идентификатора, хотя до сих пор остаются моменты, когда можно попасть в такую ситуацию. Это конечно не баг, а особенность, но даже метод removeNode в IE, который принимает параметр булевского типа, для явного указания того, что дочерние узлы должны быть удалены, в случае наличия ссылки на элемент, не делает этого :( Впрочем, так ведет себя любой объект — остается в памяти, пока есть хоть одна ссылка на него var obj = {a: 'aa'}, c = obj; obj = null; alert(c.a); Кстати, чтобы оставить в памяти удаляемый узел, нужно написать так var removedNode = parent.removeChild(node); |
Цитата:
Цитата:
Другое дело, не произойдёт ли что-либо подобное, если на чилдрена есть не прямая ссылка, а подписка на событие. Мне сегодня уже лень это проверять - завтра попробую протестить. Или если у кого-то будет еще желание этим заняться - бросьте сюда тестовый код. |
Небольшой оффтопик, с Вашего позволения...
Цитата:
Или Вы в этом случае запрещаете кэширование? Тогда, ИМХО, его надо будет запрещать в 90% случаев. А в оставшихся 10% эффективность кэша будет близка к нулю. Это по крайней мере было-бы так с теми задачами, которые мне приходилось решать. |
В документе не должно быть нескольких элементов с одним идентификатором. При смене идентификатора через специальную функцию, кэш очищается. Можно повесить обработчики, очищающие кэш, на специальные события, реагирующие на изменения структуры DOM, но я этого пока не делал, потому что в ИЕ нет этих событий. Повышение производительности при использование кэша существенно, поэтому стоит заморачиваться, темболее операции, требующие очистки кэша встречаются не так часто в большинстве скриптов.
|
Цитата:
Код:
for (var i = 0, Опера-9 довольно быстро и корректно отрабатывает сборку мусора, отъем памяти почти незаметен. Осел, ест, но, как и ожидалось, не отдает. Если убрать циклическую ссылку из замыкания (выделена жирным), то, осел вообще не ест память (либо отдает слишком быстро). Если свернуть окно осла, память освобождается, но если потом опять развернуть и еще разок прогнать цикл - достает всю кучу мусора из свопа и продолжает ее наполнять ) Сафаря-3, память отдавать не торопится - или это похожий баг, или там уборщик мусора ленивый ) |
vk65535, Большое спасибо, за тесты
|
Часовой пояс GMT +3, время: 21:07. |