[Javascript]: Создаются ли элементы с использованием метода CreateElement, вызывают утечку памяти, если они не удалены должным образом?

Я создаю элементы, используя метод createElement, и добавляю их к некоторому родительскому элементу. Позже я очистил innerHTML родительского элемента. Это приведет к утечке памяти? что происходит с созданным элементом? Если это утечка памяти, как ее обрабатывать?. также, если есть какая-либо функция обратного вызова, связанная с элементом, нужно ли ее отсоединять?

var spanelem = document.createElement('span');
spanelem.onclick = function(){
CallMe();
};
var parentdiv = document.getElementById('ParentCnt');
parentdiv.appendChild(spanelem);
.....

.....
parentdiv.innerHTML = " "; //is this memory Leak ? what happens to spanelem?

Ответ 1

Это зависит.

Если у вас есть код, который вы даете - spanElem все еще существует в памяти (если var spanelem был в глобальной области действия, и вы не выполнили spanelem = null), вы получите доступную ссылку на объект.

В противном случае, если spanElem имеет единственную ссылку из обработчика onClick - это будет утечка памяти только в IE8-. Все современные браузеры обрабатывают такие случаи и очищают память от сбора мусора.

Я предполагаю, что вы имеете в виду не тот же код, но просто принцип - в таком случае вы можете проверить, нет ли других обработчиков, которые имеют ссылку на spanElem в их лексическом env, если это так - вы можете просто очистить ссылку при добавлении

spanelem = null;

после

parentdiv.appendChild(spanelem);

Проверьте более подробную информацию в MDN

P.S. если вы запустите следующий код

var spanelem = document.createElement('span');
spanelem.onclick = function(){
CallMe();
};
var parentdiv = document.getElementById('ParentCnt');
parentdiv.appendChild(spanelem);

parentdiv.innerHTML = '';

console.log(spanelem);

вы обнаружите, что spanelem все еще существует (он будет таким же, если вы запустите   setTimeout(function(){ console.log(spanelem); }, 9999); // some huge delay here) - но единственная причина в том, что для кода ниже мы сохраняем ссылку для объекта spanelem, поэтому gc не удаляет объект. Если мы его не будем использовать, - gc удалит на нем объект

Ответ 2

В целом, если есть озабоченность в отношении сбора мусора, то для смягчения этой проблемы требуется создание закрытия для сборщика мусора для целей.

Как только все ссылки удаляются в переменную из среды переменных и лексической среды, переменная имеет право на сбор.

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

(function(){
    var spanelem = document.createElement('span');
    spanelem.onclick = function(){
        CallMe();
    };
    var parentdiv = document.getElementById('ParentCnt');
    parentdiv.appendChild(spanelem);
})()
//CONT'D

... cont'd: На этом этапе единственная ссылка остается через DOM. Использование appendChild вызывает оплату документа, и поэтому, если что-то еще, что вызывает оплату, например,.innerHTML, эта запись может быть удалена. Позже использование parentdiv.innerHTML = " " приведет к тому, что запись будет удалена, и сборщик мусора в конечном итоге, в своем собственном темпе, сможет удалить выделение памяти, если это необходимо.