Запись моментальных снимков кучи с помощью средства "Память"

Используйте профилировщик кучи в средстве "Память ", чтобы сделать следующее:

  • Запись моментальных снимков кучи JavaScript (кучи JS).
  • Анализ графов памяти.
  • Сравнение моментальных снимков.
  • Поиск утечек памяти.

Профилировщик кучи DevTools показывает распределение памяти, используемое объектами JavaScript и связанными узлами DOM на отрисовываемой веб-странице.

Возьмите snapshot

  1. Откройте веб-страницу, которую вы хотите проанализировать. Например, откройте демонстрационную страницу "Рассеянные объекты " в новом окне или вкладке.

  2. Чтобы открыть Средства разработки, щелкните веб-страницу правой кнопкой мыши и выберите пункт Проверить. Или нажмите клавиши CTRL+SHIFT+I (Windows, Linux) или COMMAND+OPTION+I (macOS). Откроется devTools.

  3. В Средствах разработки на панели действий выберите вкладку Память . Если эта вкладка не отображается, нажмите кнопку Дополнительные инструменты (значок ") .

  4. В разделе Выбор типа профилирования нажмите кнопку Snapshot кучи.

  5. В разделе Выбор экземпляра виртуальной машины JavaScript выберите виртуальную машину JavaScript, которую необходимо профилировать.

  6. Нажмите кнопку Принять snapshot:

Выбран инструмент

После загрузки новой snapshot кучи в средства разработки и анализа отображается snapshot, а на боковой панели Профили в разделе HEAP SNAPSHOTS отображается новая запись:

Общий размер доступных объектов

Число под новым элементом боковой панели показывает общий размер доступных объектов JavaScript. Дополнительные сведения о размерах объектов в куче snapshot см. в статье Размеры и расстояния объектов в терминологии памяти.

В 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, доступ к которым может получить какая-то вложенная функция. Каждый экземпляр функции содержит внутренний указатель на контекст, в котором он выполняется, чтобы он смог получить доступ к этим переменным.
(система) Различные внутренние объекты, которые еще не были классифицированы более значимым образом.

Представление сравнения

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

Чтобы убедиться, что определенные операции не создают утечки, выполните приведенные ниже действия.

  1. Перед выполнением операции сделайте кучу snapshot.

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

  3. Выполните обратную операцию. То есть сделайте обратное взаимодействие и повторите его несколько раз.

  4. Возьмите вторую кучу snapshot.

  5. Во второй куче 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 , выполните следующие действия:

  1. В DevTools нажмите кнопку Настройка и управление Средствами разработки (значок Настройка и управление средствами разработки) и нажмите кнопку Параметры (значок параметров). Или, пока devTools имеет фокус, нажмите клавишу F1.

  2. В разделе Эксперименты установите флажок В моментальных снимках кучи укажите размер резервного хранилища как часть содержащего объекта.

  3. Нажмите кнопку Закрыть (x) на странице Параметры , а затем нажмите кнопку Перезагрузить средства разработки .

  4. Возьмите новую кучу snapshot. Столбец Shallow Size теперь включает весь размер объектов:

    Столбец Мелкий размер кучи snapshot

Фильтрация моментальных снимков кучи по типам узлов

Используйте фильтры, чтобы сосредоточиться на определенных частях snapshot кучи. При просмотре всех объектов в куче snapshot в средстве "Память" может быть трудно сосредоточиться на конкретных объектах или сохранить пути.

Чтобы сосредоточиться только на определенных типах узлов, используйте фильтр Типы узлов в правом верхнем углу. Например, чтобы просмотреть только массивы и строковые объекты в куче snapshot:

  1. Чтобы открыть фильтр Типы узлов , щелкните По умолчанию в правом верхнем углу.

  2. Выберите записи Массив и Строка .

    В snapshot кучи отображаются только объекты массива и строки:

    Типы узлов в куче snapshot в средстве

Поиск определенного объекта

Чтобы найти объект в собранной куче, можно выполнить поиск с помощью клавиш CTRL+F и указать идентификатор объекта.

Обнаружение утечек DOM

Средство "Память " позволяет отображать двунаправленные зависимости, которые иногда существуют между собственными объектами браузера (узлами DOM, правилами CSS) и объектами JavaScript. Это помогает обнаруживать утечки памяти, которые происходят из-за забытых отсоединяемых узлов DOM, которые остаются в памяти.

Рассмотрим следующее дерево 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 больше, чем ожидалось , в новом окне или вкладке.

Анализ влияния замыкания на память

Чтобы проанализировать влияние замыкания на память, попробуйте следующий пример:

  1. Откройте демонстрационную веб-страницу Eval is evil в новом окне или вкладке.

  2. Запишите snapshot кучи.

  3. На отображаемой веб-странице нажмите кнопку Закрытия с вывеской .

  4. Запишите вторую кучу snapshot.

    На боковой панели число ниже второго snapshot должно быть больше, чем число ниже первого snapshot. Это означает, что веб-страница использует больше памяти после нажатия кнопки Закрытия с eval .

  5. Во второй куче snapshot измените представление на Сравнение, а затем сравните вторую кучу snapshot с первой snapshot кучи.

    В представлении Сравнение показано, что новые строки были созданы во второй куче snapshot:

    Представление сравнения, показывающее, что во второй snapshot были созданы новые строки

  6. В представлении Сравнение разверните конструктор (строка).

  7. Щелкните первую (строку) запись.

    Раздел Хранимые данные обновлен и показывает, что largeStr переменная сохраняет строку, выбранную в представлении сравнения .

    Запись largeStr автоматически разворачивается и показывает, что переменная сохраняется функцией eC , которая является закрытием, где определена переменная:

    Раздел Хранители, показывающий, что строка сохраняется функцией 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) :

Сохранение всех строк из кучи snapshot в JSON

Средство "Память" экспортирует JSON-файл, содержащий все строковые объекты из кучи snapshot:

Строки из кучи snapshot в JSON-файле

См. также

Примечание.

Части этой страницы являются изменениями, основанными на работе, созданной и совместно используемой Google и используемой в соответствии с условиями, описанными в международной лицензии Creative Commons Attribution 4.0. Исходная страница находится здесь и автор Меггин Кирни (Технический писатель).

Creative Commons License Эта работа лицензируется по международной лицензии Creative Commons Attribution 4.0.