DOM: почему это утечка памяти?
Считайте эту цитату из документов Mozilla для утечек памяти JavaScript:
function addHandler() {
var el = document.getElementById('el');
el.onclick = function() {
this.style.backgroundColor = 'red';
}
}
Приведенный выше код устанавливает элемент, чтобы он загорелся красным при его нажатии. Это также создает утечку памяти. Зачем? Поскольку ссылка на el непреднамеренно попал в закрытие, созданное для анонимного внутреннего функция. Это создает круговую ссылку между JavaScript объект (функция) и собственный объект (el).
Пожалуйста, объясните приведенные выше причины утечки простым и сжатым способом, я не получаю точную точку.
У сайта или страницы возникает проблема безопасности из-за утечки? Как мне их избежать? Какой еще код может вызвать утечку памяти? Как узнать, когда произошла утечка памяти?
Я - абсолютный новичок в теме утечек памяти. Может кто-то прояснить этот материал для меня шаг за шагом? Также может кто-то помочь мне прояснить этот оператор "Это создает круговую ссылку между объектом JavaScript (функция) и собственным объектом (el)".
Ответы
Ответ 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. Это взаимодействие между ними может вызвать утечку памяти.
И это именно то, что происходит и может вызвать утечку памяти.