Как удалить элементы DOM без утечек памяти? - PullRequest
46 голосов
/ 24 сентября 2010

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

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

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

Ответы [ 5 ]

44 голосов
/ 24 сентября 2010

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's 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);
13 голосов
/ 24 сентября 2010

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

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

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

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


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

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

8 голосов
/ 24 сентября 2010

Вы удалили каких-либо слушателей событий?Что может вызвать утечку памяти .

2 голосов
/ 24 сентября 2010

Приведенный ниже код не течет в моем браузере 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 протекает гораздо меньше, когда вы сначала вставляете узел в DOM, прежде чем что-то с ним делать, например: присоединяете к нему события или заполняете его свойство innerHTML.

1 голос
/ 06 октября 2010

Если вам нужно «исправить» утечку, и вы должны делать это без переписывания всего кода, чтобы учитывать замыкания, циклические ссылки и т. Д., Используйте Douglas Crockfords Purge-метод до удаления:

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

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

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

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