Запись моментальных снимков кучи с помощью средства "Память"
Используйте профилировщик кучи в средстве "Память ", чтобы сделать следующее:
- Запись моментальных снимков кучи JavaScript (кучи JS).
- Анализ графов памяти.
- Сравнение моментальных снимков.
- Поиск утечек памяти.
Профилировщик кучи DevTools показывает распределение памяти, используемое объектами JavaScript и связанными узлами DOM на отрисовываемой веб-странице.
Возьмите snapshot
Откройте веб-страницу, которую вы хотите проанализировать. Например, откройте демонстрационную страницу "Рассеянные объекты " в новом окне или вкладке.
Чтобы открыть Средства разработки, щелкните веб-страницу правой кнопкой мыши и выберите пункт Проверить. Или нажмите клавиши CTRL+SHIFT+I (Windows, Linux) или COMMAND+OPTION+I (macOS). Откроется devTools.
В Средствах разработки на панели действий выберите вкладку Память . Если эта вкладка не отображается, нажмите кнопку Дополнительные инструменты (") .
В разделе Выбор типа профилирования нажмите кнопку Snapshot кучи.
В разделе Выбор экземпляра виртуальной машины JavaScript выберите виртуальную машину JavaScript, которую необходимо профилировать.
Нажмите кнопку Принять snapshot:
После загрузки новой snapshot кучи в средства разработки и анализа отображается snapshot, а на боковой панели Профили в разделе HEAP SNAPSHOTS отображается новая запись:
Число под новым элементом боковой панели показывает общий размер доступных объектов JavaScript. Дополнительные сведения о размерах объектов в куче snapshot см. в статье Размеры и расстояния объектов в терминологии памяти.
В snapshot отображаются только объекты из графа памяти, доступные из глобального объекта. Выполнение snapshot всегда начинается с сборки мусора.
Еще один snapshot
Чтобы выполнить еще один snapshot, когда он уже отображается в средстве "Память", на боковой панели щелкните Профили над существующим snapshot:
Очистка моментальных снимков
Чтобы очистить все моментальные снимки из средства "Память ", щелкните значок Очистить все профили ():
Просмотр моментальных снимков
Моментальные снимки кучи можно просматривать различными способами в средстве "Память ". Каждый способ просмотра кучи snapshot в пользовательском интерфейсе соответствует другой задаче:
View | Содержимое | Используйте для |
---|---|---|
Summary | Показывает объекты, сгруппированные по имени конструктора. | Поиск объектов и используемой ими памяти на основе типов, сгруппированных по имени конструктора. Полезно для отслеживания утечек DOM. |
Comparison | Отображает различия между двумя моментальными снимками. | Сравнение двух (или более) моментальных снимков памяти до и после операции. Проверка разницы в освобожденной памяти и подсчет ссылок помогает подтвердить наличие и причину утечки памяти, а также определить ее причину. |
Ограничение | Позволяет исследовать содержимое кучи. | Обеспечивает лучшее представление о структуре объектов, помогая анализировать объекты, на которые ссылается глобальное пространство имен (окно), чтобы узнать, что хранит объекты вокруг. Используйте его для анализа закрытий и анализа объектов на низком уровне. |
Чтобы переключаться между представлениями, используйте раскрывающийся список в верхней части средства "Память ":
Примечание.
Не все свойства хранятся в куче JavaScript. Свойства, реализованные с помощью средств получения, выполняющих машинный код, не записываются. Кроме того, нестроковые значения, такие как числа, не записываются.
Сводное представление
Изначально в представлении Сводка открывается 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 создает небольшой объект, указывающий на две строки. |
InternalNode | Объекты, выделенные за пределами версии 8, например объекты C++, определенные Blink, обработчик отрисовки Microsoft Edge. |
(фигура объекта) | Сведения об объектах, такие как количество имеющихся у них свойств и ссылка на их прототипы, которые V8 поддерживает внутренне при создании и обновлении объектов. Это позволяет V8 эффективно представлять объекты с теми же свойствами. |
(срезанная строка) | При создании подстроки, например при использовании метода JavaScript substring , V8 может создать срез строковый объект, а не копировать все соответствующие символы из исходной строки. Этот новый объект содержит указатель на исходную строку и описывает диапазон символов из исходной строки для использования. |
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).
Чтобы скрыть внутренние узлы в разделе Средства хранения , в раскрывающемся меню Фильтр ребер выберите Скрыть внутренние.
Настройка столбца Shallow Size для включения размера всего объекта
По умолчанию столбец "Мелкий размер" в средстве "Память " содержит только размер самого объекта.
Мелкий размер — это размер кучи JavaScript, непосредственно удерживаемой объектом. Мелкий размер объекта обычно невелик, так как объект JavaScript часто хранит только описание объекта, а не его значения в непосредственной памяти объекта. Большинство объектов JavaScript хранят свои значения в резервном хранилище , которое находится в другом месте в куче JavaScript, и предоставляют только небольшой объект-оболочку в той части кучи JavaScript, которая непосредственно принадлежит объекту . Например, экземпляры JavaScript Array
хранят содержимое массива в резервном хранилище, которое представляет собой отдельное расположение памяти, которое не входит в небольшой размер массива.
Можно настроить столбец Shallow Size так, чтобы он сообщал весь размер объектов, включая размер резервного хранилища объекта.
Чтобы включить весь размер объектов в столбец Shallow Size , выполните следующие действия:
В DevTools нажмите кнопку Настройка и управление Средствами разработки () и нажмите кнопку Параметры (). Или, пока devTools имеет фокус, нажмите клавишу F1.
В разделе Эксперименты установите флажок В моментальных снимках кучи укажите размер резервного хранилища как часть содержащего объекта.
Нажмите кнопку Закрыть (x) на странице Параметры , а затем нажмите кнопку Перезагрузить средства разработки .
Возьмите новую кучу snapshot. Столбец Shallow Size теперь включает весь размер объектов:
Фильтрация моментальных снимков кучи по типам узлов
Используйте фильтры, чтобы сосредоточиться на определенных частях snapshot кучи. При просмотре всех объектов в куче snapshot в средстве "Память" может быть трудно сосредоточиться на конкретных объектах или сохранить пути.
Чтобы сосредоточиться только на определенных типах узлов, используйте фильтр Типы узлов в правом верхнем углу. Например, чтобы просмотреть только массивы и строковые объекты в куче snapshot:
Чтобы открыть фильтр Типы узлов , щелкните По умолчанию в правом верхнем углу.
Выберите записи Массив и Строка .
В snapshot кучи отображаются только объекты массива и строки:
Поиск определенного объекта
Чтобы найти объект в собранной куче, можно выполнить поиск с помощью клавиш CTRL+F и указать идентификатор объекта.
Обнаружение утечек DOM
Средство "Память " позволяет отображать двунаправленные зависимости, которые иногда существуют между собственными объектами браузера (узлами DOM, правилами CSS) и объектами JavaScript. Это помогает обнаруживать утечки памяти, которые происходят из-за забытых отсоединяемых узлов DOM, которые остаются в памяти.
Рассмотрим следующее дерево 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:
См. также
- Терминология памяти.
- Поиск и отладка утечек памяти в JavaScript с помощью Chrome DevTools от Gonzalo Ruiz de Villa, которая также относится к Microsoft Edge DevTools.
Примечание.
Части этой страницы являются изменениями, основанными на работе, созданной и совместно используемой Google и используемой в соответствии с условиями, описанными в международной лицензии Creative Commons Attribution 4.0. Исходная страница находится здесь и автор Меггин Кирни (Технический писатель).
Эта работа лицензируется по международной лицензии Creative Commons Attribution 4.0.