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

DOM: почему это утечка памяти?

Считайте эту цитату из документов Mozilla для утечек памяти JavaScript:

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}

Приведенный выше код устанавливает элемент, чтобы он загорелся красным при его нажатии. Это также создает утечку памяти. Зачем? Поскольку ссылка на el непреднамеренно попал в закрытие, созданное для анонимного внутреннего функция. Это создает круговую ссылку между JavaScript объект (функция) и собственный объект (el).

Пожалуйста, объясните приведенные выше причины утечки простым и сжатым способом, я не получаю точную точку.

У сайта или страницы возникает проблема безопасности из-за утечки? Как мне их избежать? Какой еще код может вызвать утечку памяти? Как узнать, когда произошла утечка памяти?

Я - абсолютный новичок в теме утечек памяти. Может кто-то прояснить этот материал для меня шаг за шагом? Также может кто-то помочь мне прояснить этот оператор "Это создает круговую ссылку между объектом JavaScript (функция) и собственным объектом (el)".

4b9b3361

Ответ 1

Есть два понятия, которые помогут вам понять этот пример.

1) Закрытие

Определение замыкания состоит в том, что Каждая внутренняя функция имеет доступ к своим родительским функциям и параметрам.

Когда функция addHandler() завершается, анонимная функция все еще имеет доступ к родительской переменной el.

2) Функции = память

Каждый раз, когда вы определяете function, создается новый объект. Что делает этот пример несколько запутанным, так это то, что onclick - это событие, которое может быть установлено только на элемент DOM один раз.

Значит, el.onclick = function(){}; просто перезапишет старую функцию правильно?

Неправильно! каждый раз, когда addHandler запускается, создается новый объект функции.

В заключение:

Каждый раз, когда запускается функция, создается новый объект с закрытием, содержащим el. Увидев, что анонимная функция поддерживает доступ к el, сборщик мусора не может удалить его из памяти.

Функция anon будет поддерживать доступ к el, а el имеет доступ к функции, которая является циклической ссылкой, которая вызывает утечку памяти в IE.

Ответ 2

Всякий раз, когда вы определяете функцию в JavaScript, для нее создается контекст выполнения; этот контекст выполнения содержит ссылки на все переменные в цепочке областей видимости, начиная с глобальной области действия вплоть до локальной области:

function test()
{
    var el = document.getElementById('el');
    el.onclick = function() {
        // execution context of this function: el, test
        alert('hello world');
    }
}

Когда test() выполняется, анонимная функция еще не переработана, поскольку теперь она назначается элементу DOM; то есть на него ссылается свойство элемента DOM.

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

Тем не менее, в настоящее время большинство движков JavaScript (даже те, что находятся в IE) используют более продвинутый сборщик мусора, который может идентифицировать неиспользуемые переменные a лучше всего, используя такие методы, как mark-and-sweep или сборка генерации/эфемерного мусора.

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

document.getElementById('el').onclick = function() {
    alert('hello world');
}

Ответ 3

Также см. раздел подробнее в статье MS по проблеме:

Эта утечка памяти возникает из-за того, что объекты DOM являются объектами, отличными от JScript. Объекты DOM не находятся в схеме сбора мусора и разметки JScript. Следовательно, круговая ссылка между объектами DOM и обработчики JScript не будут разбиты до тех пор, пока браузер полностью не будет срывает страницу.

но обратите внимание, что в отличие от того, что указано в этой статье (память будет восстановлена, когда браузер перейдет на новую страницу), эта статья подтверждает, что ошибка в IE 6 вызвала утечку памяти навсегда.

Ответ 4

Управление памятью в JavaScript обычно работает следующим образом: "до тех пор, пока это возможно, сохраните его". Это в основном парадигма, которая стоит за любой моделью памяти, управляемой мусором.

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

Однако в вашем примере у вас есть два объекта из двух разных "миров":

Circular references

Internet Explorer использует для этого собственную схему сбора мусора, отдельно от механизма, используемого JavaScript. Это взаимодействие между ними может вызвать утечку памяти.

И это именно то, что происходит и может вызвать утечку памяти.