使用記憶體工具記錄堆積快照集

使用 記憶體 工具中的堆積分析工具來執行下列動作:

  • 記錄 JavaScript 堆積 (JS 堆積) 快照集。
  • 分析記憶體圖形。
  • 比較快照集。
  • 尋找記憶體流失。

DevTools 堆積分析工具會顯示 JavaScript 對象和轉譯網頁上相關 DOM 節點所使用的記憶體分佈。

擷取快照集

  1. 開啟您要分析的網頁。 例如,在新的視窗或索引標籤中開啟 [散佈物件 ] 示範頁面。

  2. 若要開啟 DevTools,請以滑鼠右鍵按兩下網頁,然後選取 [ 檢查]。 或者,按 Ctrl+Shift+I (Windows、Linux) 或 Command+Option+I (macOS) 。 DevTools 隨即開啟。

  3. 在 DevTools 的 [ 活動列] 上,選取 [ 記憶體] 索引 標籤。如果看不到該索引標籤,請按兩下 [ 其他工具 ] ([ 其他工具] 圖示) 按鈕。

  4. 在 [ 選取分析類型] 區段中,選取 [ 堆積快照集 ] 選項按鈕。

  5. [選取 JavaScript VM 實例] 下,選取您要分析的 JavaScript VM。

  6. 按兩下 [ 擷取快照集 ] 按鈕:

已選取 [記憶體] 工具、[堆積快照集] 選項,並醒目提示 [擷取快照集] 按鈕

將新錄製的堆積快照集載入 DevTools 並進行剖析之後,就會顯示快照集,並在 [配置 ] 提要字段的 [ HEAP SNAPSHOTS] 下方顯示新的專案:

可連線物件的大小總計

新提要字段專案下方的數字會顯示可連線 JavaScript 物件的總大小。 若要深入瞭解堆積快照中的物件大小,請參閱記憶體術語中的物件大小和距離

快照集只會顯示可從全域物件連線的記憶體圖形中的物件。 擷取快照一律會從垃圾收集開始。

擷取另一個快照集

若要在 記憶體 工具中顯示另一個快照集時擷取另一個快照集,請在提要字段中,按兩下現有快照集上方 的 [配置檔 ]:

要擷取另一個快照集的 [配置檔] 按鈕

清除快照集

若要清除 記憶體 工具中的所有快照集,請按兩下 [清除所有設定檔 ] (清除圖示) 圖示:

拿掉快照集

檢視快照集

您可以在 記憶體 工具中以多種方式檢視堆積快照集。 在 UI 中檢視堆積快照集的每個方式都會對應至不同的工作:

檢視 內容 用途
摘要 顯示依建構函式名稱分組的物件。 根據依建構函式名稱分組的類型,尋找物件及其使用的記憶體。 有助於追蹤 DOM 流失。
比較 顯示兩個快照集之間的差異。 比較作業前後的兩個 (或多個) 記憶體快照集。 檢查釋放的記憶體中的差異並檢查參考計數,可協助您確認記憶體流失的存在和原因,並協助判斷其原因。
遏制措施 允許探索堆積內容。 提供更好的對象結構檢視,協助分析全域命名空間 (視窗中所參考的物件,) 找出物件周圍保留的內容。 使用它來分析關閉,並深入瞭解低階的物件。

若要在檢視之間切換,請使用 記憶體 工具頂端的下拉式清單:

切換檢視選取器

從堆積快照集省略的專案

使用執行原生程式代碼的 getter 實作的屬性不會擷取到堆積快照集,因為這類屬性不會儲存在 JavaScript 堆積上。

不會擷取非字串值,例如數位。

摘要檢視

記憶體工具中的 [摘要] 檢視會列出:

  • 物件建構函式群組。
  • 特殊類別名稱,例如 (數位列) (編譯的程式代碼) 或屬性清單 ,例如 {foo、bar、baz}

一開始,堆積快照集會在 [ 摘要 ] 檢視中開啟,其中會顯示建構函式清單:

摘要檢視

您可以展開清單中的每個建構函式,以顯示使用該建構函式具現化的物件。

對於清單中的每個建構函式, [摘要 ] 檢視也會顯示一個數位 ,例如 ×123,指出使用建構函式建立的物件總數。 [ 摘要] 檢視 也會顯示下列數據行:

欄名稱 描述
Distance (距離) 使用節點的最短簡單路徑來顯示根目錄的距離。 請參閱記憶體術語中的距離
淺層大小 顯示特定建構函式所建立之所有對象的淺層大小總和。 淺層大小是物件直接持有的 JavaScript 堆積大小。 對象的淺層大小通常很小,因為 JavaScript 物件通常只會將物件的描述儲存在物件的直接保留記憶體中,而非值。 大部分的 JavaScript 物件都會將其值儲存在 JavaScript 堆積中其他位置的支援 存放 區中,而且只會在物件直接擁有的 JavaScript 堆積部分公開小型包裝函式物件。 請參閱記憶體術語中的淺層大小
保留大小 顯示相同物件集之間的保留大小上限。 (刪除物件之後,您可以釋放的記憶體大小,而且) 稱為保留大小,就無法再連線到相依專案。 請參閱記憶體術語中的保留大小

在 [ 摘要 ] 檢視中展開建構函式之後,會顯示建構函式的所有實例。 針對每個實例,淺層和保留的大小會顯示在相對應的數據行中。 字元後面 @ 的數位是物件的唯一標識符,可讓您比較每個物件的堆積快照集。

建構函式專案

記憶體工具中的 [摘要] 檢視會列出物件建構函式群組:

建構函式群組

[ 摘要 ] 檢視中的建構函式群組可能是內建函式,例如 ArrayObject,或者它們可能是您自己的程式代碼中定義的函式。

若要顯示由指定建構函式具現化的物件清單,請展開建構函式群組。

特殊類別名稱

記憶體工具中的 [摘要] 檢視包含下列特殊類別名稱,這些名稱不是以建構函式為基礎。 這些類別名稱大多以括號顯示。

類別名稱 描述
(陣列) 各種類似數位的內部物件,不會直接對應至從 JavaScript 可見的物件,例如 JavaScript 陣列的內容,或 JavaScript 物件的具名屬性。
(編譯的程式代碼) V8 (Microsoft Edge JavaScript 引擎) 的內部數據,必須執行 JavaScript 或 WebAssembly 所定義的函式。 V8 會自動管理此類別中的記憶體使用量:如果函式執行多次,V8 會針對該函式使用更多記憶體,讓函式執行速度更快。 如果函式有一段時間未執行,V8 可能會刪除該函式的內部數據。
(串連字串) 當兩個字串串連在一起時,例如使用JavaScript + 運算符時,V8可能會選擇在內部將結果表示為 串連字串串。 V8 不會將這兩個字串的所有字元複製到新的字串中,而是會建立指向兩個字串的小型物件。
(物件圖形) 對象的相關信息,例如它們擁有的屬性數目,以及其原型的參考,V8 會在建立和更新物件時於內部維護。 這可讓 V8 有效率地代表具有相同屬性的物件。
(配量字串) 建立子字串時,例如使用 JavaScript substring 方法時,V8 可能會選擇建立 已配量的字串 物件,而不是從原始字串複製所有相關字元。 這個新的 物件包含原始字串的指標,並描述要使用原始字串中的字元範圍。
(系統) 尚未以更有意義的方式分類的各種內部物件。
{foo, bar, baz} 依介面 (屬性清單) ,以大括號分類的純 JavaScript 物件。 純 JavaScript 物件不會列在名為 Object 的類別中,而是以物件所包含屬性為基礎的名稱和類別來表示,例如 {foo、bar、baz}
InternalNode 配置在 V8 外部的物件,例如C++ Blink 所定義的物件,Microsoft Edge 的轉譯引擎。
system / Context 來自 JavaScript 範圍的局部變數,可由某些巢狀函式存取。 每個函式實例都包含執行內容的內部指標,以便存取這些變數。

比較檢視

若要尋找外洩的物件,請比較多個快照集彼此。 在 Web 應用程式中,通常執行動作,然後反向動作不應該導致記憶體中有更多的物件。 例如,開啟檔然後關閉檔時,記憶體中的物件數目應該與開啟檔之前相同。

若要確認特定作業不會造成流失:

  1. 執行作業之前,請先擷取堆積快照集。

  2. 執行作業。 也就是說,以某種方式與頁面互動,可能會造成流失。

  3. 執行反向作業。 也就是說,執行相反的互動並重複幾次。

  4. 擷取第二個堆積快照集。

  5. 在第二個堆積快照集中,將檢視變更為 [比較],並將其與 快照集 1 進行比較。

在 [ 比較] 檢視 中,會顯示兩個快照集之間的差異:

比較檢視

展開清單中的建構函式時,會顯示新增和刪除的物件實例。

內含項目檢視

[ 內含專案 ] 檢視可讓您查看函式關閉內部、觀察虛擬機 (VM) 組成 JavaScript 物件的內部物件,以及瞭解應用程式在非常低層級使用多少記憶體:

內含項目檢視

[ 內含專案] 檢視 會顯示下列類型的物件:

內含項目檢視進入點 描述
DOMWindow 物件 JavaScript 程式代碼的全域物件。
GC 根目錄 JavaScript 虛擬機的垃圾收集行程所使用的 GC 根目錄。 GC 根目錄是由內建對象對應、符號數據表、VM 線程堆疊、編譯快取、句柄範圍和全域句柄所組成。
原生物件 瀏覽器所建立的物件,例如 DOM 節點和 CSS 規則,這些規則會顯示在 JavaScript 虛擬機中以允許自動化。

[保留器] 區段

[保留器] 區段會顯示在 [記憶體] 工具的底部,並顯示指向所選物件的所有物件。 當您在 [摘要]、[內含專案] 或 [比較] 檢視中選取不同的物件時,會更新 [保留器] 區段。

在下列螢幕快照中,已在 [摘要] 檢視中選取字串物件,而 [保留器] 區段會顯示字串是由 檔案中example-03.js找到的 類別實例的 Item 屬性所x保留:

[保留器] 區段

隱藏迴圈

在 [ 保留器] 區段中 ,當您分析保留所選物件的物件時,可能會遇到 迴圈。 當相同物件在所選物件的保留器路徑中出現一次以上時,就會發生迴圈。 在 [ 保留器] 區 段中,迴圈物件會以灰色表示。

若要協助簡化保留程式路徑,請在 [ 保留器 ] 區段中隱藏迴圈,方法是按兩下 [ 篩選邊緣 ] 下拉功能表,然後選取 [ 隱藏迴圈]

已選取 [保留器] 區段中的 [篩選邊緣] 下拉功能表[隱藏迴圈]

隱藏內部節點

內部節點 是 Microsoft Edge) 中 JavaScript 引擎 (V8 專屬的物件。

若要從 [ 保留器 ] 區段隱藏內部節點,請在 [ 篩選邊緣 ] 下拉功能表中,選取 [ 隱藏內部]

依節點類型篩選堆積快照集

使用篩選器來專注於堆積快照集的特定部分。 在 記憶體工具 中查看堆積快照集中的所有物件時,可能很難專注於特定物件或保留路徑。

若只要專注於特定類型的節點,請使用右上方的 [節點類型 ] 篩選條件。 例如,若只要查看堆積快照集中的數位和字串物件:

  1. 若要開啟 [節點類型] 篩選,請按下右上方的 [ 預設 ]。

  2. 選取 [ 列] 和 [字串] 專案。

    堆積快照集會更新為只顯示數位和字串物件:

    記憶體工具中堆積快照集內的節點類型

尋找特定物件

若要在收集的堆積中尋找物件,您可以使用 Ctrl+F 進行搜尋,並提供物件識別碼。

發現 DOM 流失

記憶體工具能夠顯示瀏覽器原生物件 (DOM 節點、CSS 規則) 和 JavaScript 物件之間有時存在的雙向相依性。 這有助於探索因遺忘中斷連結的 DOM 節點保留在記憶體中而發生的記憶體流失。

請考慮下列 DOM 樹狀結構:

DOM 子樹

下列程式代碼範例會建立 JavaScript 變數 treeRefleafRef,其參考樹狀結構中的兩個 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"> 垃圾收集元素,因為 JavaScript 變數 treeRef 仍然存在。 變數 treeRef 會直接參考 <div id="tree"> 專案。 在下列程式代碼範例中 treeRef ,變數為 Null:

// Remove the treeRef variable.
treeRef = null;

專案 <div id="tree"> 仍然無法進行垃圾收集,因為 JavaScript 變數 leafRef 仍然存在。 屬性 leafRef.parentNode<div id="tree"> 參考 專案。 在下列程式代碼範例中 leafRef ,變數為 Null:

// Remove the leafRef variable.
leafRef = null;

此時, <div id="tree"> 可以垃圾收集元素。 和 leafRef 都必須treeRef先為 Null,才能將元素下的<div id="tree">整個 DOM 樹狀結構進行垃圾收集。

示範網頁:範例 6:洩漏 DOM 節點

若要瞭解 DOM 節點可能流失的位置,以及如何偵測這類外洩,請開啟範例網頁範例 6:在新的視窗或索引標籤中 洩漏 DOM 節點

示範網頁:範例 9:DOM 流失大於預期

若要查看 DOM 流失可能大於預期的原因,請在新的視窗或索引卷標中開啟範例網頁 範例 9:DOM 流失大於預期

分析關閉對記憶體的影響

若要分析關閉對記憶體的影響,請嘗試此範例:

  1. 在新的視窗或索引標籤中開啟 Eval is 評估 示範網頁。

  2. 記錄堆積快照集。

  3. 在轉譯的網頁中,按兩下 [ 使用驗證關閉 ] 按鈕。

  4. 記錄第二個堆積快照集。

    在提要欄位中,第二個快照集下方的數字應該大於第一個快照集下方的數位。 這表示網頁在按兩下 [使用驗證關閉 ] 按鈕之後 ,會使用更多的記憶體。

  5. 在第二個堆積快照集中,將檢視變更為 [比較],然後比較第二個堆積快照集與第一個堆積快照集。

    [ 比較] 檢視 會顯示已在第二個堆積快照中建立新的字串:

    [比較] 檢視,顯示已在第二個快照中建立新的字串串

  6. 在 [ 比較] 檢視 中,展開 (字串) 建構函式。

  7. 按兩下第一 個 (字串) 專案。

    [ 保留器 ] 區段會更新,並顯示 largeStr 變數會保留在 [比較] 檢視 中選取的字串。

    專案 largeStr 會自動展開,並顯示函式會 eC 保留變數,也就是定義變數的關閉位置:

    [保留器] 區段,顯示 eC 函式會保留字串

秘訣:命名函式,以區別快照中的關閉

若要輕鬆區分堆積快照中的 JavaScript 關閉,請提供函式名稱。

下列範例會使用未命名的函式來傳回 largeStr 變數:

function createLargeClosure() {
    const largeStr = 'x'.repeat(1000000).toLowerCase();

    // This function is unnamed.
    const lC = function() {
        return largeStr;
    };

    return lC;
}

下列範例會將函式命名為 ,讓您更輕鬆地區分堆積快照中的關閉:

function createLargeClosure() {
    const largeStr = 'x'.repeat(1000000).toLowerCase();

    // This function is named.
    const lC = function lC() {
        return largeStr;
    };

    return lC;
}

將字串從堆積快照集儲存並匯出至 JSON

記憶體 工具中擷取堆積快照集時,您可以將快照集的所有字串對象匯出至 JSON 檔案。 在 [記憶體] 工具的 [建構函式] 區段中,按兩下專案旁邊的 (string) [全部儲存至檔案] 按鈕:

將堆積快照集的所有字串儲存至 JSON

記憶體工具會匯出 JSON 檔案,其中包含堆積快照集的所有字串物件:

JSON 檔案中堆積快照集的字串

另請參閱

注意事項

此頁面的部分是根據Google所建立和 共用的工作進行 修改,並根據 Creative Commons Attribution 4.0 國際授權中所述的條款使用。 原始頁面 可在這裡 找到,並由 Meggin Kearney (Technical Writer) 所撰寫。

Creative Commons 授權 此工作是根據 Creative Commons Attribution 4.0 International License 授權