2015-03-03 3 views
0

enter image description here Я профилировал мое веб-приложение в Chrome Developer Tools и придумал график, показанный выше. Я создаю и удаляю элементы как функции зависания. Я читал об этом в this article.Является ли это утечкой памяти Javascript?

Этот шаблон указывает, что у меня есть утечка памяти? Счет узла (зеленая линия) постоянно растет, а не падает на внутренние GC. Но падает на ноль на моем принудительном GC. Это обычное поведение?

Я имею в виду, что он содержит много узлов в памяти, хотя их нет. Если я проверю кучу , ссылки на DOM-узлы отсутствуют (без detached-DOM и т. Д.), Что заставляет меня думать, что это не утечка памяти?

Каковы ваши пять центов?

код ниже:

$(document).on("mouseenter", ".btn", function(e){ 
    var el = document.createElement("div"); 
    el.id = "box"; 
    document.body.appendChild(el); 
}); 
$(document).on("mouseleave", ".btn", function(e){ 
    $("#box").remove(); 
}); 
+0

Если на принудительной GC падает 0, то утечек нет. –

ответ

3

Я не вижу утечки памяти в трассировке вы показываете из Chrome. Недостающей части информации является то, что , когда запущен цикл сбора мусора, возможно для цикла частично собрать мусор. Позволь мне объяснить.

Я не знаком с сборщиком мусора в версии 8, но в разное время в прошлом работал над сборщиками мусора. Сбор мусора является балансирующим действием между быстрым освобождением неиспользуемой памяти и быстродействием приложения. В интерактивных приложениях, в частности, вы не хотите приостанавливать выполнение в течение длительного времени, чтобы обеспечить полный цикл сбора мусора, поскольку это повлияет на опыт пользователя. Таким образом, существуют стратегии, согласно которым циклы сбора мусора могут быть частично, а не полный.Кажется, что v8 использует такую ​​стратегию, потому что Google's blurb on v8's garbage collection государства:

Это означает, что V8:

исполнение
  • остановки программы при выполнении цикла сбора мусора.
  • обрабатывает только часть кучи объекта в большинстве циклов сбора мусора. Это минимизирует влияние остановки приложения.

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

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

+0

Спасибо, сэр, это был именно тот случай. Оказывается, мусор собирает некоторые узлы и оставляет некоторые в памяти. Полная принудительная GC очищает все, что, в свою очередь, означает отсутствие утечки памяти. 200p до Гриффиндора! – Eric

0

Не 100% уверен в этом, но я думаю, что этот вопрос может быть вашим MouseEnter/MouseLeave события не развязывание?

2

Хорошо, давайте попробуем решить эту проблему.

Возможности:

Как работа управления памятью Javascript? Это все на достижимости:

  1. Отличительное множество объектов предполагаются достижима: это известны как корни. Как правило, они включают в себя все объекты , на которые ссылаются из любой точки стека вызовов (то есть все локальные переменные и параметры в вызываемых в настоящее время функциях), и любые глобальные переменные.
  2. Объекты хранятся в памяти, пока они доступны из корней через ссылку или цепочку ссылок.

http://javascript.info/tutorial/memory-leaks

Так в основном, JS будет удалить объект из памяти, когда он недоступен. Давайте попробуем пример:

HTML:

<html> 
<div class="ourDiv"></div> 
</html> 

JS:

$(".ourDiv").append(document.createElement("span")) 
      .remove(); 

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

  1. мы имеем HTML, тело и DIV тегов в памяти
  2. мы добавляющие срок до ourDiv, так что мы имеем в памяти HTML, теле, отде и пролета теги
  3. после удаления ourDiv, пролет элемента недостижим так в памяти мы имеем: HTML и тела теги

Давайте изменим его, чтобы быть более похожим на ваш Код:

JS:

var newEl=document.createElement("span"); 
newEl.id = "ourSpan"; 
$(".ourDiv").append(newEl) 
      .remove(); 

Как это работает сейчас?

Элемент #id является исключением. Доступно как #ourSpan, поэтому остается в памяти. Конечно, если вы проверите его parentNode, это будет null.

  1. мы имеем HTML, тело и ДИВО тегов в памяти
  2. мы добавляющие пролет с удостоверением к ourDiv, так что мы имеем в памяти HTML, тело, отд и пролетные тегов
  3. после удаления ourDiv, пролет элемента по-прежнему доступен, как это ID установлен так, в памяти мы имеем: HTML, тело и оболочка

Вывод:

Поскольку вы устанавливаете ID для каждого созданного элемента, javascript будет иметь его в памяти, даже когда вы попытаетесь удалить их с помощью вызова jQuery. Вероятно, это из-за смешивания создающего элемента с собственным API и удаления его в jQuery. Попытайтесь проверить свой размер $.cache - если он слишком большой, это означает, что jQuery неправильно удаляет объекты.

Но прежде всего - избегать использования идентификатора для ваших постоянно создаваемых элементов.

Это больше объяснено: Chrome Javascript docs, Firefox Javascript Docs

Смежные вопросы