Подтвердить что ты не робот

Как удалить элементы DOM без утечек памяти?

Мой код JavaSript создает список элементов LI. Когда я обновляю список, использование памяти растет и никогда не опускается. Я тестировал sIEve, и он показывает, что браузер сохраняет все элементы, которые должны были быть удалены с помощью команд $.remove() или $.empty jQuery.

Что делать, чтобы удалить узлы DOM без утечки памяти?

См. мой другой вопрос для конкретного кода.

4b9b3361

Ответ 1

DOM сохраняет все узлы DOM, даже если они были удалены из самого дерева DOM, единственный способ удалить эти узлы - это обновить страницу (если вы поместите список в iframe, обновление не будет как примечательный)

В противном случае вы можете дождаться, когда проблема станет настолько плохой, что сборщик мусора браузера будет принудительно задействован (здесь говорят сотни мегабайт неиспользуемых узлов)

Лучшей практикой является повторное использование узлов.

РЕДАКТИРОВАТЬ: Попробуйте следующее:

var garbageBin;
window.onload = function ()
    {
    if (typeof(garbageBin) === 'undefined')
        {
        //Here we are creating a 'garbage bin' object to temporarily 
        //store elements that are to be discarded
        garbageBin = document.createElement('div');
        garbageBin.style.display = 'none'; //Make sure it is not displayed
        document.body.appendChild(garbageBin);
        }
    function discardElement(element)
        {
        //The way this works is due to the phenomenon whereby child nodes
        //of an object with it innerHTML emptied are removed from memory

        //Move the element to the garbage bin element
        garbageBin.appendChild(element);
        //Empty the garbage bin
        garbageBin.innerHTML = "";
        }
    }

Чтобы использовать его в своем контексте, вы бы сделали это следующим образом:

discardElement(this);

Ответ 2

Это скорее FYI, чем фактический ответ, но это также довольно интересно.

Из спецификации ядра W3C DOM (http://www.w3.org/TR/DOM-Level-2-Core/core.html):

API-интерфейсы Core DOM разработаны для обеспечения совместимости с широким спектром языков, включая языки сценариев общего пользования и более сложные языки, используемые в основном профессиональными программистами. Таким образом, API-интерфейсы DOM должны работать с различными философиями управления памятью, от языковых привязок, которые вообще не предоставляют пользователю управление памятью через те (в частности, Java), которые предоставляют явные конструкторы, но автоматически предоставляют автоматический механизм сбора мусора вернуть неиспользуемую память тем (особенно C/С++), которые обычно требуют, чтобы программист явно выделял память объекта, отслеживал, где он используется, и явно освобождает его для повторного использования. Чтобы обеспечить согласованный API на этих платформах, DOM вообще не затрагивает проблемы управления памятью, но вместо этого оставляет их для реализации. Ни одно из явных языковых привязок, определенных DOM API (для ECMAScript и Java), не требует каких-либо методов управления памятью, но для привязки DOM для других языков (особенно C или С++) может потребоваться такая поддержка. Эти расширения будут нести ответственность за адаптацию DOM API к определенному языку, а не к рабочей группе DOM.

Другими словами: управление памятью остается для реализации спецификации DOM на разных языках. Вам нужно будет изучить документацию по реализации DOM в javascript, чтобы узнать какой-либо метод удаления объекта DOM из памяти, который не является взломом. (Однако на сайте MDC очень мало информации по этой теме.)


Как примечание к jQuery#remove и jQuery#empty: из того, что я могу сказать, ни один из этих методов не делает ничего, кроме удаления Object из DOM node или удаления DOM node из document > . Они только удаляют. Это, конечно, не означает, что для этих объектов нет памяти, хотя они больше не находятся в document.

Изменить: Вышеприведенный отрывок был лишним, поскольку, очевидно, jQuery не может творить чудеса и работать с реализацией DOM используемого браузера.

Ответ 4

Код ниже не распространяется на мои IE7 и другие браузеры:

<html>
<head></head>
<body>
    <a href="javascript:" onclick="addRemove(this)">add</a>
    <ul></ul>
    <script>
        function addRemove(a) {
            var ul = document.getElementsByTagName('UL')[0],
                li, i = 20000;
            if (a.innerHTML === 'add') {
                while (i--) {
                    li = document.createElement('LI');
                    ul.appendChild(li);
                    li.innerHTML = i;
                    li.onclick = function() {
                        alert(this.innerHTML);
                    };
                }
                a.innerHTML = 'remove';
            } else {
                while (ul.firstChild) {
                    ul.removeChild(ul.firstChild);
                }
                a.innerHTML = 'add';
            }
        }
    </script>
    </body>
</html>

Может быть, вы можете попытаться выявить некоторые отличия от вашего кода.
Я знаю, что IE течет гораздо меньше, когда вы вставляете сначала node в DOM, прежде чем что-либо делать с ним, например: присоединять к нему события или заполнять его свойство innerHTML.

Ответ 5

Если вам нужно "укрепить" утечку и сделать это, не переписывая весь свой код для закрытия, круговых ссылок и т.д. в учетной записи, используйте Douglas Crockfords Purge-method перед удалением:

http://javascript.crockford.com/memory/leak.html

Или используйте обходное решение для закрытия:

http://laurens.vd.oever.nl/weblog/items2005/closures/