使用堆快照

你可以從正在執行的應用程式中獲取堆快照,並將其載入到 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. 查詢大的正增量,並在底部面板中探索導致它們的原因引用。

你可以透過這個堆快照練習來練習捕獲堆快照和查詢記憶體洩漏。