Запись моментальных снимков кучи с помощью средства "Память" (тип профилирования "Куча snapshot")
Используйте профилировщик кучи в средстве "Память ", чтобы сделать следующее:
- Запись моментальных снимков кучи JavaScript (кучи JS).
- Анализ графов памяти.
- Сравнение моментальных снимков.
- Поиск утечек памяти.
Профилировщик кучи DevTools показывает распределение памяти, используемое объектами JavaScript и связанными узлами DOM на отрисовываемой веб-странице.
Возьмите snapshot
Откройте веб-страницу, которую вы хотите проанализировать. Например, откройте демонстрационную страницу "Рассеянные объекты " в новом окне или вкладке.
Чтобы открыть Средства разработки, щелкните веб-страницу правой кнопкой мыши и выберите пункт Проверить. Или нажмите клавиши CTRL+SHIFT+I (Windows, Linux) или COMMAND+OPTION+I (macOS). Откроется devTools.
В Средствах разработки на панели действий выберите вкладку Память . Если эта вкладка не отображается, нажмите кнопку Дополнительные инструменты (") .
В разделе Выбор типа профилирования нажмите кнопку Snapshot кучи.
В разделе Выбор экземпляра виртуальной машины JavaScript выберите виртуальную машину JavaScript, которую необходимо профилировать.
Нажмите кнопку Принять snapshot:
После загрузки snapshot новой кучи в средства разработки и анализа отображается snapshot, а на боковой панели Профили в разделе Моментальные снимки кучи появится новая запись:
Число под новым элементом боковой панели показывает общий размер доступных объектов JavaScript. Дополнительные сведения о размерах объектов в куче snapshot см. в статье Размеры и расстояния объектов в терминологии памяти.
В snapshot отображаются только объекты из графа памяти, доступные из глобального объекта. Выполнение snapshot всегда начинается с сборки мусора.
Еще один snapshot
Чтобы выполнить еще один snapshot, когда он уже отображается в средстве "Память", на боковой панели щелкните Профили над существующим snapshot:
Очистка моментальных снимков
Чтобы очистить все моментальные снимки из средства "Память ", щелкните значок Очистить все профили ():
Просмотр моментальных снимков
Моментальные снимки кучи можно просматривать различными способами в средстве "Память ". Каждый способ просмотра кучи snapshot в пользовательском интерфейсе соответствует другой задаче:
Просмотр | Содержимое | Используйте для |
---|---|---|
Summary | Показывает объекты, сгруппированные по имени конструктора. | Поиск объектов и используемой ими памяти на основе типов, сгруппированных по имени конструктора. Полезно для отслеживания утечек DOM. |
Comparison | Отображает различия между двумя моментальными снимками. | Сравнение двух (или более) моментальных снимков памяти до и после операции. Проверка разницы в освобожденной памяти и подсчет ссылок помогает подтвердить наличие и причину утечки памяти, а также определить ее причину. |
Ограничение | Позволяет исследовать содержимое кучи. | Обеспечивает лучшее представление о структуре объектов, помогая анализировать объекты, на которые ссылается глобальное пространство имен (окно), чтобы узнать, что хранит объекты вокруг. Используйте его для анализа закрытий и анализа объектов на низком уровне. |
Чтобы переключаться между представлениями, используйте раскрывающийся список в верхней части средства "Память ":
Элементы, пропущенные из моментальных снимков кучи
Свойства, реализованные с помощью средств получения, выполняющих машинный код, не записываются в кучу snapshot, так как такие свойства не хранятся в куче JavaScript.
Нестроковые значения, такие как числа, не записываются.
Сводное представление
В представлении Сводка в средстве "Память " перечислены следующие списки:
- Группы конструкторов объектов.
- Специальные имена категорий, такие как (массив),(скомпилированный код) или список свойств, таких как {foo, bar, baz}.
Изначально в представлении Сводка открывается snapshot куча, в которой отображается список конструкторов:
Каждый конструктор в списке можно развернуть, чтобы отобразить объекты, экземпляры которых были созданы с помощью этого конструктора.
Для каждого конструктора в списке в представлении Сводка также отображается число , например ×123, указывающее общее количество объектов, созданных с помощью конструктора. В представлении Сводка также отображаются следующие столбцы:
Столбец | Описание |
---|---|
Distance (Расстояние) | Отображает расстояние до корня, используя самый короткий простой путь узлов. См. раздел Расстояние в терминологии памяти. |
Неглубокий размер | Отображает сумму мелких размеров всех объектов, созданных определенной функцией конструктора. Мелкий размер — это размер кучи JavaScript, непосредственно удерживаемой объектом. Мелкий размер объекта обычно невелик, так как объект JavaScript часто хранит только описание объекта, а не его значения в непосредственной памяти объекта. Большинство объектов JavaScript хранят свои значения в резервном хранилище , которое находится в другом месте в куче JavaScript, и предоставляют только небольшой объект-оболочку в той части кучи JavaScript, которая непосредственно принадлежит объекту . См. раздел Мелкий размер в терминологии памяти. |
Сохраненный размер | Отображает максимальный сохраненный размер для одного и того же набора объектов. Размер памяти, которую можно освободить после удаления объекта (а зависимые объекты становятся недоступными), называется сохраненным размером. См. раздел Сохраненный размер в терминологии памяти. |
После развертывания конструктора в представлении Сводка отображаются все экземпляры конструктора. Для каждого экземпляра мелкие и сохраненные размеры отображаются в соответствующих столбцах. Число после символа @
является уникальным идентификатором объекта, что позволяет сравнивать моментальные снимки кучи по каждому объекту.
Записи конструктора
В представлении Сводка в средстве "Память " перечислены группы конструкторов объектов:
Группы конструкторов в представлении Сводка могут быть встроенными функциями, такими как Array
или Object
, или функциями, определенными в вашем собственном коде.
Чтобы отобразить список объектов, экземпляры которые были созданы заданным конструктором, разверните группу конструкторов.
Специальные имена категорий
Представление Сводка в средстве "Память " содержит следующие специальные имена категорий, которые не основаны на конструкторах. Большинство из этих имен категорий отображаются в круглых скобках.
Имя категории | Описание |
---|---|
(массив) | Различные внутренние объекты, подобные массиву, которые напрямую не соответствуют объектам, видимым из JavaScript, например содержимому массивов JavaScript или именованным свойствам объектов JavaScript. |
(скомпилированный код) | Внутренние данные, необходимые версии 8 (обработчик JavaScript Microsoft Edge) для выполнения функций, определенных JavaScript или WebAssembly. Версия 8 автоматически управляет использованием памяти в этой категории: если функция выполняется много раз, V8 использует больше памяти для этой функции, чтобы функция выполнялось быстрее. Если функция некоторое время не выполнялась, версия 8 может удалить внутренние данные для этой функции. |
(объединенная строка) | Если две строки объединяются вместе, например при использовании оператора JavaScript + , V8 может представить результат внутри в виде сцепленной строки. Вместо копирования всех символов двух строк в новую строку V8 создает небольшой объект, указывающий на две строки. |
(фигура объекта) | Сведения об объектах, такие как количество имеющихся у них свойств и ссылка на их прототипы, которые V8 поддерживает внутренне при создании и обновлении объектов. Это позволяет V8 эффективно представлять объекты с теми же свойствами. |
(срезанная строка) | При создании подстроки, например при использовании метода JavaScript substring , V8 может создать срез строковый объект, а не копировать все соответствующие символы из исходной строки. Этот новый объект содержит указатель на исходную строку и описывает диапазон символов из исходной строки для использования. |
(система) | Различные внутренние объекты, которые еще не были классифицированы более значимым образом. |
{foo, bar, baz} | Обычные объекты JavaScript, классифицированные по интерфейсу (списку свойств), в фигурных скобках. Обычные объекты JavaScript не перечислены в категории с именем Object, но вместо этого представлены именами и категориями, основанными на свойствах, содержащихся в объекте, таких как {foo, bar, baz}. |
InternalNode | Объекты, выделенные за пределами версии 8, например объекты C++, определенные Blink, обработчик отрисовки Microsoft Edge. |
system / Context | Локальные переменные из область JavaScript, доступ к которым может получить какая-то вложенная функция. Каждый экземпляр функции содержит внутренний указатель на контекст, в котором он выполняется, чтобы он смог получить доступ к этим переменным. |
Представление сравнения
Чтобы найти утечку объектов, сравните несколько моментальных снимков друг с другом. В веб-приложении обычно выполняется действие, а затем обратное действие не должно приводить к увеличению объема объектов в памяти. Например, при открытии и последующем закрытии документа количество объектов в памяти должно быть таким же, как и перед открытием документа.
Чтобы убедиться, что определенные операции не создают утечки, выполните приведенные ниже действия.
Перед выполнением операции сделайте кучу snapshot.
Выполните операцию. То есть взаимодействовать со страницей каким-то образом, что может привести к утечке.
Выполните обратную операцию. То есть сделайте обратное взаимодействие и повторите его несколько раз.
Возьмите вторую кучу snapshot.
Во второй куче snapshot измените представление на Сравнение, сравнив его с моментальным снимком 1.
В представлении Сравнения отображается разница между двумя моментальными снимками:
При расширении конструктора в списке отображаются добавленные и удаленные экземпляры объектов.
Представление "Автономное"
Представление Containment позволяет заглянуть внутрь закрытия функций, наблюдать за внутренними объектами виртуальных машин, составляющими объекты JavaScript, и понять, сколько памяти приложение использует на очень низком уровне:
В представлении Containment отображаются следующие типы объектов:
Точки входа в представление "Автономное" | Описание |
---|---|
Объекты DOMWindow | Глобальные объекты для кода JavaScript. |
Корни мусора | Корневые данные сборки мусора, используемые сборщиком мусора виртуальной машины JavaScript. Корневые элементы сборки мусора состоят из встроенных карт объектов, таблиц символов, стеков потоков виртуальных машин, кэшей компиляции, областей дескрипторов и глобальных дескрипторов. |
Собственные объекты | Объекты, созданные браузером, такие как узлы DOM и правила CSS, которые отображаются на виртуальной машине JavaScript для обеспечения автоматизации. |
Раздел Хранимые средства
Раздел Хранители отображается в нижней части средства "Память " и отображает все объекты, указывающие на выбранный объект. Раздел Средства хранения обновляется при выборе другого объекта в представлении Сводка, Содержание или Сравнение .
На следующем снимке экрана в представлении Сводка был выбран строковый объект, а в разделе Хранимые данные показано, что строка сохраняется свойством x
экземпляра класса, найденного Item
в example-03.js
файле:
Скрытие циклов
В разделе Хранители при анализе объектов, которые хранят выбранный объект, могут возникнуть циклы. Циклы возникают, когда один и тот же объект появляется несколько раз в пути к средству хранения выбранного объекта. В разделе Хранители циклический объект обозначается серым цветом.
Чтобы упростить путь к хранителю, скройте циклы в разделе Средства хранения , щелкнув раскрывающееся меню Фильтр ребер , а затем выбрав Скрыть циклическое:
Скрытие внутренних узлов
Внутренние узлы — это объекты, относящиеся к версии 8 (подсистема JavaScript в Microsoft Edge).
Чтобы скрыть внутренние узлы в разделе Средства хранения , в раскрывающемся меню Фильтр ребер выберите Скрыть внутренние.
Фильтрация моментальных снимков кучи по типам узлов
Используйте фильтры, чтобы сосредоточиться на определенных частях snapshot кучи. При просмотре всех объектов в куче snapshot в средстве "Память" может быть трудно сосредоточиться на конкретных объектах или сохранить пути.
Чтобы сосредоточиться только на определенных типах узлов, используйте фильтр Типы узлов в правом верхнем углу. Например, чтобы просмотреть только массивы и строковые объекты в куче snapshot:
Чтобы открыть фильтр Типы узлов , щелкните По умолчанию в правом верхнем углу.
Выберите записи Массив и Строка .
В snapshot кучи отображаются только объекты массива и строки:
Поиск определенного объекта
Чтобы найти объект в собранной куче, можно выполнить поиск с помощью клавиш CTRL+F и указать идентификатор объекта.
Обнаружение утечек DOM
Средство "Память " позволяет отображать двунаправленные зависимости, которые иногда существуют между собственными объектами браузера (узлами DOM, правилами CSS) и объектами JavaScript. Это помогает обнаруживать утечки памяти, которые происходят из-за забытых отсоединяемых узлов DOM, которые остаются в памяти.
Сведения об отсоединяемых элементах см. также в разделе Поиск утечек памяти дерева DOM ("Куча snapshot" тип > профилирования Detached) ниже.
Рассмотрим следующее дерево DOM:
В следующем примере кода создаются переменные treeRef
JavaScript и leafRef
, которые ссылались на два узла DOM в дереве:
// Get a reference to the #tree element.
const treeRef = document.querySelector("#tree");
// Get a reference to the #leaf element,
// which is a descendant of the #tree element.
const leafRef = document.querySelector("#leaf");
В следующем примере <div id="tree">
кода элемент удаляется из дерева DOM:
// Remove the #tree element from the DOM.
document.body.removeChild(treeRef);
Элемент <div id="tree">
не может быть собран при сборке мусора, так как переменная treeRef
JavaScript все еще существует. Переменная treeRef
напрямую ссылается на <div id="tree">
элемент . В следующем примере treeRef
кода переменная получает значение NULL:
// Remove the treeRef variable.
treeRef = null;
Элемент <div id="tree">
по-прежнему не может быть собран при сборке мусора, так как переменная leafRef
JavaScript по-прежнему существует. Свойство leafRef.parentNode
ссылается на <div id="tree">
элемент . В следующем примере leafRef
кода переменная получает значение NULL:
// Remove the leafRef variable.
leafRef = null;
На этом этапе <div id="tree">
элемент может быть собран с помощью мусора. Оба treeRef
элемента leafRef
и должны сначала быть обнуляемы, чтобы все дерево DOM в элементе <div id="tree">
было собрано мусором.
Демонстрационная веб-страница. Пример 6. Утечка узлов DOM
Чтобы понять, где могут протекать узлы DOM и как обнаружить такую утечку, откройте пример веб-страницы Пример 6. Утечка узлов DOM в новом окне или вкладке.
Демонстрационная веб-страница. Пример 9. Утечки DOM больше, чем ожидалось
Чтобы узнать, почему утечка DOM может быть больше, чем ожидалось, откройте пример веб-страницы Пример 9. Утечки DOM больше, чем ожидалось , в новом окне или вкладке.
Анализ влияния замыкания на память
Чтобы проанализировать влияние замыкания на память, попробуйте следующий пример:
Откройте демонстрационную веб-страницу Eval is evil в новом окне или вкладке.
Запишите snapshot кучи.
На отображаемой веб-странице нажмите кнопку Закрытия с вывеской .
Запишите вторую кучу snapshot.
На боковой панели число ниже второго snapshot должно быть больше, чем число ниже первого snapshot. Это означает, что веб-страница использует больше памяти после нажатия кнопки Закрытия с eval .
Во второй куче snapshot измените представление на Сравнение, а затем сравните вторую кучу snapshot с первой snapshot кучи.
В представлении Сравнение показано, что новые строки были созданы во второй куче snapshot:
В представлении Сравнение разверните конструктор (строка).
Щелкните первую (строку) запись.
Раздел Хранимые данные обновлен и показывает, что
largeStr
переменная сохраняет строку, выбранную в представлении сравнения .Запись
largeStr
автоматически разворачивается и показывает, что переменная сохраняется функциейeC
, которая является закрытием, где определена переменная:
Совет. Назовите функции для различения закрытий в snapshot
Чтобы легко различать закрытия JavaScript в куче snapshot, присвойте имена функций.
В следующем примере для возврата largeStr
переменной используется неименованная функция:
function createLargeClosure() {
const largeStr = 'x'.repeat(1000000).toLowerCase();
// This function is unnamed.
const lC = function() {
return largeStr;
};
return lC;
}
В следующем примере функция называется, что упрощает распознавание замыкания в куче snapshot:
function createLargeClosure() {
const largeStr = 'x'.repeat(1000000).toLowerCase();
// This function is named.
const lC = function lC() {
return largeStr;
};
return lC;
}
Сохранение и экспорт строк из кучи snapshot в JSON
При выполнении кучи snapshot в средстве "Память" можно экспортировать все строковые объекты из snapshot в JSON-файл. В средстве Память в разделе Конструктор нажмите кнопку Сохранить все в файл рядом с записью (string)
:
Средство "Память" экспортирует JSON-файл, содержащий все строковые объекты из кучи snapshot:
Поиск утечек памяти дерева DOM (тип > профилирования "Куча snapshot" Отсоединен)
Один из способов найти и отобразить все отсоединенные элементы на веб-странице — использовать snapshot типа профилирования средства "Память", а затем в текстовом поле Фильтр по классам введите Отсоединенные, как показано ниже. См. также статью Средства для исследования отсоединяемых элементов в статье Устранение проблем с памятью.
Следующий код создает отсоединяемые узлы DOM:
var detachedTree;
function create() {
var ul = document.createElement('ul');
for (var i = 0; i < 10; i++) {
var li = document.createElement('li');
ul.appendChild(li);
}
detachedTree = ul;
}
document.getElementById('create').addEventListener('click', create);
Этот код создает узел с десятью ul
li
дочерними элементами. На узлы ссылается код, но они не существуют в дереве DOM, поэтому каждый узел отсоединяется.
Моментальные снимки кучи — это один из способов идентификации отсоединяемых узлов. Куча snapshot показывает, как память распределяется между объектами JS и узлами DOM для страницы в момент snapshot.
Использование типа профилирования "Куча snapshot" для поиска отсоединяемых элементов
Чтобы использовать тип профилирования Snapshot Куча для поиска отсоединяемых элементов, выполните следующие действия:
Откройте веб-страницу, например демонстрационную веб-страницу Отсоединенные элементы, в новом окне или вкладке.
Щелкните веб-страницу правой кнопкой мыши и выберите Пункт Проверить. Или нажмите клавиши CTRL+SHIFT+I (Windows, Linux) или COMMAND+OPTION+I (macOS).
Откроется devTools.
В Средствах разработки на панели действий выберите Память (память).
Если эта вкладка не отображается, нажмите кнопку Дополнительные инструменты ( и выберите Память. Откроется средство "Память ":
Если кнопка "Куча snapshot" не отображается, так как профиль уже отображается, в левом верхнем углу щелкните Профили ().
На этом этапе не нужно нажимать кнопку Куча snapshot, так как веб-страница еще не создает отсоединенные элементы.
Создайте сообщения, которые будут храниться экземпляром JavaScript класса Room:
На демонстрационной веб-странице нажмите кнопку Быстрый трафик .
Демонстрационная веб-страница начинает создавать сообщения и отображать их на веб-странице:
После отображения некоторых сообщений нажмите кнопку Остановить на демонстрационной веб-странице.
Каждое сообщение является элементом
<div class="message">
, на который ссылается экземплярRoom
Класса Room 1. В дереве DOM веб-страницы нет отсоединяемых элементов, так как все элементы сообщения присоединяются к настоящему экземпляру класса Room 1.Измените на другой экземпляр класса Room, чтобы элементы стали отсоединяться:
На демонстрационной веб-странице нажмите кнопку Комната 2 , которая соответствует другому экземпляру
Room
класса .На веб-странице сообщения исчезают:
Сообщения, созданные для экземпляра Room 1 класса Room (
<div class="message">
элементы), больше не присоединяются к DOM, но на них по-прежнему ссылается экземпляр Room 1 класса Room . Они являются отсоединяемыми элементами, которые могут привести к утечке памяти, если они не будут использоваться снова веб-страницей.Получите список отсоединяемых элементов:
В средствах разработки в средстве "Память " щелкните значок Сбор мусора (:
Браузер запускает сборку мусора, удаляя все узлы, на которые больше не ссылается объект JavaScript.
В средстве "Память" нажмите кнопку Snapshot кучи.
Нажмите кнопку Принять snapshot в нижней части средства "Память".
Snapshot обрабатывается, загружается, а затем отображается на боковой панели Профили в разделе Моментальные снимки кучи.
В текстовом поле Фильтровать по классам введите detached:
Отсоединенные элементы DOM, которые не могут быть собраны в мусор.
Определите код JavaScript, который ссылается на конкретный отсоединяемый элемент:
В snapshot кучи разверните отсоединяемый объект, например Отсоединяемый <div>, а затем выберите узел Отсоединяемый <div class="message".>
Сведения отображаются в области Средства хранения в нижней части средства "Память ".
В области Средства хранения щелкните ссылку
room.js:13
для отключенного элемента в помещении в разделе Массив. Откроется инструмент Источники с прокрученнымroom.js
до строки 13:Чтобы проверить возможную утечку памяти, изучите код, использующий
unmounted
массив, и убедитесь, что ссылка на узел удаляется, когда она больше не нужна.Чтобы вернуться к средству "Память ", в адресной строке выберите средство "Память ".
Дополнительные способы просмотра отсоединяемых элементов см. в статье Средства для исследования отсоединяемых элементов в статье Устранение проблем с памятью.
См. также
- Средства для исследования отсоединяемых элементов в статье Устранение проблем с памятью.
- Терминология памяти
Внешний:
- Поиск и отладка утечек памяти в JavaScript с помощью Chrome DevTools ( Gonzalo Ruiz de Villa), которая также относится к Microsoft Edge DevTools.
Примечание.
Части этой страницы являются изменениями, основанными на работе, созданной и совместно используемой Google и используемой в соответствии с условиями, описанными в международной лицензии Creative Commons Attribution 4.0. Исходная страница находится здесь и автор Меггин Кирни.
Эта работа лицензируется по международной лицензии Creative Commons Attribution 4.0.