使用堆快照

你可以从正在运行的应用程序中获取堆快照,并将其加载到 Chrome 开发者工具中,以检查某些变量或查看保留大小。你还可以比较多个快照以查看随时间的变化。

警告

创建快照时,主线程中的所有其他工作都会停止。根据堆内容,这甚至可能需要一分钟以上。快照是在内存中构建的,因此它可能会使堆大小加倍,从而导致内存被完全填满,然后应用程序崩溃。

如果你要在生产环境中进行堆快照,请确保你正在操作的进程崩溃不会影响应用程序的可用性。

操作方法

获取堆快照

有多种方法可以获取堆快照:

  1. 通过检查器 (inspector),
  2. 通过外部信号和命令行标志,
  3. 通过在进程内调用 writeHeapSnapshot
  4. 通过检查器协议。

1. 在检查器中使用内存分析

适用于所有正在积极维护的 Node.js 版本

使用 --inspect 标志运行 node 并打开检查器。 打开检查器

获取堆快照的最简单方法是连接检查器到本地运行的进程。然后转到“内存”选项卡并获取堆快照。

take a heap snapshot

2. 使用 --heapsnapshot-signal 标志

适用于 v12.0.0 或更高版本

你可以通过一个命令行标志启动 node,使其能够响应信号来创建堆快照。

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

有关详细信息,请参阅 heapsnapshot-signal 标志的最新文档。

3. 使用 writeHeapSnapshot 函数

适用于 v11.13.0 或更高版本。在旧版本中可使用 heapdump 包

如果你需要从一个正在运行的进程(例如在服务器上运行的应用程序)获取快照,你可以通过以下方式实现:

('v8').();

查看 writeHeapSnapshot 文档了解文件名选项。

你需要一种在不停止进程的情况下调用它的方法,因此建议在 HTTP 处理程序中或作为对操作系统信号的响应来调用它。注意不要暴露触发快照的 HTTP 端点。不应让任何其他人能够访问它。

对于 v11.13.0 之前的 Node.js 版本,你可以使用 heapdump 包

4. 使用检查器协议触发堆快照

检查器协议可用于从进程外部触发堆快照。

使用该 API 并不需要运行 Chromium 的实际检查器。

这是一个在 bash 中使用 websocatjq 的快照触发示例

#!/bin/bash
set -e

kill -USR1 "$1"
rm -f fifo out
mkfifo ./fifo
websocat -B 10000000000 "$(curl -s https://: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>&-

这是一个可与检查器协议一起使用的内存分析工具的不完全列表

如何使用堆快照查找内存泄漏

你可以通过比较两个快照来发现内存泄漏。重要的是要确保快照差异不包含不必要的信息。以下步骤应该可以产生干净的快照差异。

  1. 让进程加载所有源文件并完成引导。这最多需要几秒钟。
  2. 开始使用你怀疑泄漏内存的功能。它可能会进行一些初始分配,这些分配不是泄漏的部分。
  3. 获取一个堆快照。
  4. 继续使用该功能一段时间,最好在此期间不要运行任何其他程序。
  5. 获取另一个堆快照。两者之间的差异应该主要包含泄漏的内容。
  6. 打开 Chromium/Chrome 开发者工具并转到“内存”选项卡
  7. 首先加载较旧的快照文件,然后再加载较新的文件。 工具中的加载按钮
  8. 选择较新的快照,并在顶部的下拉菜单中将模式从“摘要”切换到“比较”。 比较下拉菜单
  9. 查找大的正增量,并在底部面板中探索导致它们的原因引用。

你可以通过这个堆快照练习来练习捕获堆快照和查找内存泄漏。