Javascript + теги IMG = утечка памяти. Есть лучший способ это сделать?

У меня есть веб-страница, которая использует jquery для получения некоторой информации о продукте, когда люди смотрят на вещи, а затем отображает последние изображения продуктов, которые были просмотрены. Это в обратном вызове jquery AJAX, который выглядит примерно так:

if (number_of_things_seen > 10) {
  $('#shots li:last-child').remove();
}

$('<li><img src = "' + p.ProductImageSmall + '"></li>').prependTo('#shots');

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

Инспектор DOM Safari показывает, что DOM такая, как я ожидал, но, похоже, поддерживает ссылки на каждое отображаемое изображение (как показано в этот скриншот на случай, если кому-то интересно).

Я добавил

$('#shots li:last-child img').remove();

К заявлению об удалении без заметного эффекта.

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

Вам удалось найти утечку? Мне было бы интересно, если бы вы это сделали.

Tomalak 08.12.2008 20:58

Нет. Он все еще течет как сумасшедший. Я сделал другую версию приложения, которая имеет существенно другой механизм отображения, но я все еще вижу утечку изображений.

Dustin 09.12.2008 06:16

Когда вы пишете тестовый пример, скажем, один тег img и цикл JavaScript, который заменяет его атрибут src из кучи URL-адресов (без JS-фреймворка, только большой статический массив URL-адресов и трехстрочный цикл) - он все еще протекает ? Если так, то вам не повезло, если не все исправить.

Tomalak 09.12.2008 13:48

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

Grumpy 25.09.2011 14:49
Асинхронная передача данных с помощью sendBeacon в JavaScript
Асинхронная передача данных с помощью sendBeacon в JavaScript
В современных веб-приложениях отправка данных из JavaScript на стороне клиента на сервер является распространенной задачей. Одним из популярных...
Принципы ООП в JavaScript
Принципы ООП в JavaScript
Парадигма объектно-ориентированного программирования имеет 4 основных принципа,
Laravel с Turbo JS
Laravel с Turbo JS
Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием...
Слишком много useState? Давайте useReducer!
Слишком много useState? Давайте useReducer!
Современный фронтенд похож на старую добрую веб-разработку, но с одной загвоздкой: страница в браузере так же сложна, как и бэкенд.
Типы данных JavaScript
Типы данных JavaScript
В JavaScript существует несколько типов данных, включая примитивные типы данных и ссылочные типы данных. Вот краткое объяснение различных типов данных...
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик Модуль flexbox, также известный как гибкий модуль разметки box, помогает эффективно проектировать и...
8
4
3 830
8

Ответы 8

Можете ли вы попробовать изменить src последнего ребенка и посмотреть, имеет ли это значение? Затем вы можете переместить этот элемент, чтобы он стал первым дочерним элементом

//not tested

var $list=$('#shots>li');
$list.filter(':last-child').children('img')
.attr('src', p.ProductImageSmall)
.parent()
.insertBefore( $list.eq(0) );

Мне нравится код, к которому привело это предложение, но изображения все еще не исчезают.

Dustin 03.12.2008 10:32

Дастин, когда ты говоришь, что изображения не исчезают, ты можешь уточнить? Вы имеете в виду, что он не меняет местами изображения?

redsquare 03.12.2008 11:05

Это странно, так как удаление в jquery оптимизировано для предотвращения утечек. может быть, это создание утечек xhr-объектов?

redsquare 03.12.2008 11:07

До того, как я стал показывать изображения, они просачивались гораздо медленнее - что-то порядка миллиона обновлений, прежде чем я увидел, что оно превышает 100 МБ.

Dustin 03.12.2008 11:21

Дастин, можешь уточнить, не работала ли смена src изображения?

redsquare 03.12.2008 11:22

Да, я сделал почти в точности тот код. Я инициализировал список из 10 элементов с прозрачным изображением размером 1 пиксель и циклически прокрутил их таким образом (установив src и title для каждого из них). Увидел ту же проблему роста изображения.

Dustin 03.12.2008 11:36

Как долго вы наблюдаете, как это «бесконечно растет»? некоторые реализации сборщиков мусора не обязательно возвращают память ОС так быстро, если вообще возвращают. Можете ли вы превратить то, что вы пытаетесь сделать, в настоящий простой тест (например, многократно настраивая src изображения) без ajax или обратных вызовов? Вы можете попробовать это с другими браузерами?

Я дал ему поработать несколько часов и пролистал несколько тысяч товаров. Я не мог понять, что это когда-либо освобождает.

Dustin 03.12.2008 10:21

Вероятно ли, что это произойдет в реальном мире?

redsquare 03.12.2008 10:26

@redsquare Определенно. Это визуализация использования продукта компании. Я ожидаю, что они оставят это на весь день. Изображения выглядят очень красиво, но мне, возможно, придется вытащить их, если браузер взорвется в загруженные дни.

Dustin 03.12.2008 10:35

@Scott Safari утекал память медленнее, чем firefox, но я на самом деле не пытался выяснить, что firefox делает с памятью. Хотя я совершенно уверен, что дело в самих изображениях.

Dustin 03.12.2008 10:37

Из Центр разработчиков Mozilla на removeChild():

The removed child node still exists in memory, but is no longer part of the DOM. You may reuse the removed node later in your code, via the oldChild object reference.

Это ключ - повторно использовать удаленный дочерний элемент вместо того, чтобы многократно создавать новый.

// I'm sure there is a nicer way to do it in jQuery
if (number_of_things_seen > 10) {
  var shots = document.getElementById("shots");
  var li    = shots.getElementsByTagName("LI");
  var move  = shots.removeChild(li[li.length-1]);
  move.getElementsByTagName("IMG")[0].src = p.ProductImageSmall;
  shots.insertBefore(move, li[0]);
}

Это в значительной степени то, что меня заставляло делать redsquare. Это работает, но не предотвращает утечку. : /

Dustin 03.12.2008 12:01

Вырастет ли он так же, если вы просто переместите ребенка, не касаясь src?

Tomalak 03.12.2008 12:18

И - действительно ли вы пробовали нет, используя для этого jQuery (например, попробуйте подход только на JS)? Может быть, сам jQuery все еще как-то отвечает.

Tomalak 03.12.2008 12:21

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

См. http://pastebin.me/4936458820c43

Я не вижу, чтобы количество изображений в сафари увеличивалось. Полагаю, это неплохо. Я думаю, что это +1 теория xhr. Однако я не совсем понимаю, у кого есть ссылка на img.

Dustin 03.12.2008 11:47

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

Dustin 03.12.2008 12:01

Дастин, Кажется, что оператор insertBefore в моем коде вызывал некоторые проблемы. Если вы видите этот следующий тестовый пример, использование памяти остается довольно статичным, хотя я очищаю последний дочерний элемент и вставляю новый новый фрагмент dom. Работает лучше, чем последняя попытка.

Http://pastebin.me/4936519fea2cf

Является ли след действительно проблемой?

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

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

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

window.setTimeout("location.reload()",1000*60*60);//refresh in an hour

Можно изменить, чтобы он обновлялся только в том случае, если пользователь ничего не делал в течение 5 минут или около того.

Georg Schölly 13.05.2009 00:22

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

Это можно обойти, переместив изображения в CSS:

if (number_of_things_seen > 10) {
  $('#shots li:last-child').remove();
}

$('<li><div style = "background-image: url(\'' + p.ProductImageSmall +
     '\'); background-repeat: no-repeat; background-position: center; '+
     ' width: 20px; height: 20px"></div></li>').prependTo('#shots');

Проверьте, решает ли это вашу утечку памяти.

Другие вопросы по теме