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

Как предотвратить утечку памяти при удалении изображений в DOM?

Существует известная ошибка в webkit, которая при удалении изображения из DOM не освобождает связанную с ним память.

Это проблема с одностраничными приложениями, которые часто загружают изображения.

Различные предлагаемые решения:

Первые 3 метода для меня не работают. Основным недостатком для рециркуляции элементов изображения является то, что он означает запись большого количества кода для управления этим. Я загружаю новый HTML через AJAX, который может содержать изображения, поэтому я не обязательно знаю количество загружаемых изображений.

Есть ли какие-нибудь другие проблемы, чтобы решить эту проблему?

4b9b3361

Ответ 1

Я использовал 3 разных типа подходов...

Первая. Добавил набор изображений и оставил сборку мусора в браузере. enter image description here

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

Второй. Использовал данные: шаблоны URI для src для изображений.

var s = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";

for (var i = 0; i < 100; i++){
    var img = document.createElement("img");
    img.src = s;
document.getElementById("myList1").appendChild(img);
setTimeout(function(){img = null;}, 1000);
}

enter image description here

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

Третий. Сбор мусора в коде.

var s = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";

for (var i = 0; i < 100; i++){
    var img = document.createElement("img");
    img.src = "dot.png";  // or the other, both mean the same here.
    img.src = s;
document.getElementById("myList1").appendChild(img);
setTimeout(function(){img = null;}, 1000);
}

enter image description here

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

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

Ответ 2

Основной пул изображений должен позволить вам повторно использовать элементы img для повторного использования. Так как вы не знаете, сколько изображений будет достигнуто заранее, просто размер пула будет расширяться по мере необходимости.

Что-то вроде этого должно работать:

    function getImg( id, src, alt ) {
        var pool = document.getElementById( 'image_pool' );
        var img = ( pool.children.length > 0 ) ? pool.removeChild( pool.children[0] ) : document.createElement( 'img' );
        img.id = id;
        img.src = src;
        img.alt = alt;
        return img;
    }
    function recycleImg( id ) {
        var img = document.getElementById( id );
        document.getElementById( 'image_pool' ).appendChild( img.parentNode.removeChild( img ) );
    }

Поместите скрытый контейнер "image_pool" на вашей странице где-нибудь, чтобы скрыть переработанные изображения между использованием:

<div id="image_pool" style="display:none;"></div>

Затем в любое время, когда вам понадобится новый элемент img, вызовите:

document.getElementById( 'some_element_id' ).appendChild( getImg( 'my_image_id', 'images/hello.gif', 'alt_text' ) );

И когда вы закончите с ним:

recycleImg( 'my_image_id' );

альтернатива jQuery

    function getImg( id, src, alt ) {
        var img;
        if( $("#image_pool").children().length > 0 ) {
            return $("#image_pool img:first-child").attr( { 'id': id, 'src': src, 'alt': alt } ).detach();
        }
        return $( "<img />'" ).attr( { 'id': id, 'src': src, 'alt': alt } );
    }
    function recycleImg( id ) {
        $( "#" + id ).detach().appendTo( $("#image_pool") );
    }

Если вам нужен новый элемент img:

getImg( 'my_image_id', 'images/hello.gif', 'alt_text' ).appendTo( $( "#some_element_id" ) );

(утилизация работает так же, как указано выше)

Ответ 3

Попробуйте установить для дерева объектов DOM объект "null".

Во-первых, используя что-то вроде интерфейса инструмента разработчика Chrome, найдите объект в иерархии дерева DOM и осмотрите его и найдите объект, содержащий двоичный файл вашего изображения.

Попробуйте установить для этого объекта значение null, например var obj = null;.

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

Ответ 4

Установка на null была решением по крайней мере здесь. (Firefox 69)

В проекте я загружаю множество изображений партиями от 1 до 5 для сравнения. Изображения в среднем 8-9MB. Без установки элементов img на null после удаления накопление ОЗУ было значительным и исчерпывало доступную память.

Итак, изменилось с этого:

function clear (n) {
    while (n.lastChild) {
        n.removeChild(n.lastChild);
    return n;
};

на это:

function clear (n) {
    let x;
    while (n.lastChild) {
        x = n.removeChild(n.lastChild);
        x = null;
    }
    return n;
};

Теперь нет никакого накопления ОЗУ.

Ответ 5

Как установить изображения в качестве фонов в div? Я считаю, что Flickr делает что-то подобное для своего мобильного приложения html5.