На этой странице

Вы можете снять Heap Snapshot (снимок кучи) с работающего приложения и загрузить его в Chrome Developer Tools, чтобы инспектировать определённые переменные или проверить размер удерживающих ссылок (retainer). Можно также сравнивать несколько снапшотов, чтобы увидеть различия во времени.

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

Если вы собираетесь снимать heap snapshot в production, убедитесь, что процесс, с которого вы его снимаете, может упасть, не влияя на доступность вашего приложения.

Есть несколько способов получить heap snapshot:

  1. через inspector,
  2. через внешний сигнал и флаг командной строки,
  3. через вызов writeHeapSnapshot внутри процесса,
  4. через протокол inspector.

Работает во всех активно поддерживаемых версиях Node.js

Запустите node с флагом --inspect и откройте inspector. ![открыть inspector][open inspector image]

Самый простой способ получить Heap Snapshot — подключить inspector к вашему процессу, работающему локально. Затем перейдите на вкладку Memory и снимите heap snapshot.

![снять heap snapshot][take a heap snapshot image]

Работает в v12.0.0 или новее

Можно запустить node с флагом командной строки, включающим реакцию на сигнал для создания heap snapshot.

$ node --heapsnapshot-signal=SIGUSR2 index.js

Подробнее см. актуальную документацию флага heapsnapshot-signal.

Работает в v11.13.0 или новее Может работать в более старых версиях с пакетом heapdump

Если вам нужен снапшот с работающего процесса, например приложения, работающего на сервере, вы можете реализовать его получение так:

Смотрите документацию writeHeapSnapshot для опций имени файла.

Вам нужен способ вызвать её, не останавливая процесс, поэтому советуем вызывать её в HTTP-обработчике или как реакцию на сигнал операционной системы. Будьте осторожны, чтобы не выставить наружу HTTP-эндпоинт, инициирующий снапшот. Ни у кого другого не должно быть возможности до него достучаться.

Для версий Node.js до v11.13.0 можно использовать пакет heapdump.

Протокол inspector можно использовать, чтобы инициировать Heap Snapshot извне процесса.

Чтобы использовать этот API, не обязательно запускать настоящий inspector из Chromium.

Вот пример триггера снапшота в bash, с использованием websocat и jq:

#!/bin/bash
set -e

kill -USR1 "$1"
rm -f fifo out
mkfifo ./fifo
websocat -B 10000000000 "$(curl -s http://localhost:9229/json | jq -r '.[0].webSocketDebuggerUrl')" < ./fifo > ./out &
exec 3>./fifo
echo '{"method": "HeapProfiler.enable", "id": 1}' > ./fifo
echo '{"method": "HeapProfiler.takeHeapSnapshot", "id": 2}' > ./fifo
while jq -e "[.id != 2, .result != {}] | all" < <(tail -n 1 ./out); do
  sleep 1s
  echo "Capturing Heap Snapshot..."
done

echo -n "" > ./out.heapsnapshot
while read -r line; do
  f="$(echo "$line" | jq -r '.params.chunk')"
  echo -n "$f" >> out.heapsnapshot
  i=$((i+1))
done < <(cat out | tail -n +2 | head -n -1)

exec 3>&-

Вот неполный список инструментов профилирования памяти, пригодных для использования с протоколом inspector:

Найти утечку памяти можно, сравнив два снапшота. Важно убедиться, что разница между снапшотами не содержит лишней информации. Следующие шаги должны дать чистый diff между снапшотами.

  1. Дайте процессу загрузить все исходники и закончить бутстрап. Это должно занять максимум несколько секунд.
  2. Начните использовать функциональность, которую вы подозреваете в утечке памяти. Скорее всего, она делает некоторые начальные аллокации, которые не являются утекающими.
  3. Снимите один heap snapshot.
  4. Продолжайте использовать функциональность какое-то время, желательно не запуская ничего другого в промежутке.
  5. Снимите ещё один heap snapshot. Разница между двумя должна в основном содержать то, что утекало.
  6. Откройте dev tools в Chromium/Chrome и перейдите на вкладку Memory
  7. Загрузите сначала более старый файл снапшота, а вторым — более новый. ![Кнопка Load в инструментах][load button image]
  8. Выберите более новый снапшот и переключите режим в выпадающем списке сверху с Summary на Comparison. ![Выпадающий список Comparison][comparison image]
  9. Ищите большие положительные дельты и исследуйте ссылки, которые их вызвали, в нижней панели.

Вы можете попрактиковаться в снятии heap snapshot и поиске утечек памяти с этим упражнением по heap snapshot.