修正記憶體問題

瞭解如何使用 Chrome 和開發人員工具找出影響網頁效能的記憶體問題,包括記憶體流失、記憶體過多,以及經常收集的垃圾收集。

摘要

  • 透過 Chrome 工作管理員,查看網頁目前的記憶體用量。
  • 透過時間軸記錄,以圖表呈現長期的記憶體用量。
  • 使用堆積快照找出卸離的 DOM 樹狀結構 (發生記憶體流失的常見原因)。
  • 透過配置時間軸記錄,在 JS 堆積中分配新記憶體的時間。

總覽

基於 RAIL 效能模型的精神,您應該將重點放在效能工作上。

記憶體問題非常重要,因為使用者常能察覺。使用者可以透過下列方式察覺記憶體問題:

  • 網頁的效能會隨著時間逐漸降低。這可能像是記憶體流失記憶體流失是指網頁中的錯誤,會隨著時間的推移,逐步使用更多記憶體和更多記憶體。
  • 網頁效能持續不佳。這可能是記憶體過度的現象。記憶體配置是指網頁使用的記憶體超過最佳網頁速度所需的記憶體量。
  • 網頁效能延遲或經常暫停。這可能是經常垃圾收集的現象「垃圾收集」是指瀏覽器收回記憶體的時間。瀏覽器會做出決定。集合期間,所有指令碼都會暫停執行。因此,如果瀏覽器進行大量垃圾收集,指令碼執行作業就會經常暫停。

記憶體膨脹:多少「太多」?

記憶體流失的定義很簡單,如果網站逐步使用更多的記憶體,就可能發生流失。但是記憶體過度會比較不容易固定。什麼情況算是「使用過多記憶體」?

由於裝置和瀏覽器各有不同的功能,因此不適用這項數據。 在高階智慧型手機上順利執行的網頁,可能會在低階智慧型手機上當機。

關鍵在於使用 RAIL 模型,並將焦點放在使用者身上。找出使用者最常用的裝置,然後在這些裝置上測試你的網頁。如果使用體驗持續不佳,代表網頁可能超出這些裝置的記憶體功能。

透過 Chrome 工作管理員即時監控記憶體用量

您可以使用 Chrome 工作管理員,著手調查記憶體問題。工作管理員是一個即時監控器,可讓您瞭解頁面目前的記憶體使用量。

  1. 按下 Shift+Esc 鍵或前往 Chrome 主選單,然後依序選取「更多工具」 >「工作管理員」以開啟工作管理員。

    正在開啟工作管理員

  2. 對工作管理員的表格標頭按一下滑鼠右鍵,啟用「JavaScript 記憶體」

    啟用 JS 記憶體

這兩個資料欄會針對網頁記憶體用量提供不同的資訊:

  • 「Memory」(記憶體) 資料欄代表原生記憶體。DOM 節點儲存在原生記憶體中。如果這個值增加,系統正在建立 DOM 節點。
  • 「JavaScript 記憶體」欄代表 JS 堆積。此欄包含兩個值。您感興趣的值是實際數字 (括號中的數字)。即時數字代表頁面上可存取物件的記憶體用量。如果這個數量持續增加,表示系統正在建立新物件,或是現有物件持續增加。

透過效能記錄以視覺化的方式呈現記憶體流失情形

您也可以使用「成效」面板,做為調查的另一個起點。「效能」面板可協助您以視覺化方式呈現頁面的記憶體用量變化。

  1. 開啟開發人員工具中的「Performance」面板。
  2. 勾選「Memory」(記憶體) 核取方塊。
  3. 錄影

如要示範效能記憶體錄製過程,請考慮以下程式碼:

var x = [];

function grow() {
  for (var i = 0; i < 10000; i++) {
    document.body.appendChild(document.createElement('div'));
  }
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

每當使用者按下程式碼中參照的按鈕時,都會將一萬 div 節點附加至文件主體,而 100 萬個 x 字元的字串會推送至 x 陣列。執行這段程式碼會產生時間軸記錄,如以下螢幕截圖所示:

簡單的成長範例

首先是使用者介面的說明。「Overview」窗格 (「NET」下方) 中的「HEAP」圖表代表 JS 堆積。「Overview」(總覽) 窗格下方是「Counter」(計數器) 窗格。您可以在這裡查看按 JS 堆積細分的記憶體用量 (與「總覽」窗格中的「HEAP」圖表相同)、文件、DOM 節點、事件監聽器和 GPU 記憶體。停用核取方塊後,圖表中就不會顯示該核取方塊。

這是程式碼與螢幕截圖的分析結果。如果您查看節點計數器 (綠色圖表),會發現它與程式碼完全一致。節點數量會在不同的步驟增加。您可以假設節點數的每次增加都是對 grow() 的呼叫。JS 堆積圖 (藍色圖形) 不這麼簡單,為了遵循最佳做法,第一個低點其實是強制垃圾收集 (按下「collect garbage」按鈕中所達成)。隨著記錄進展,您會看到 JS 堆積大小激增。這是正常現象:JavaScript 程式碼會在每次點選按鈕時建立 DOM 節點,且所建立的字串為一百萬個字元,因此處理了許多工作。重點在於 JS 堆積的結束時間大於開始時間 (這裡的「開始」是強制垃圾收集之後的時間點)。實際上,如果您在實際環境中看到這種增加 JS 堆積大小或節點大小的模式,可能表示記憶體流失。

透過堆積快照找出卸離的 DOM 樹狀結構記憶體流失情形

只有在網頁的 DOM 樹狀結構或 JavaScript 程式碼沒有參照 DOM 節點的情況下,系統才會對 DOM 節點進行垃圾收集。從 DOM 樹狀結構中移除節點,但部分 JavaScript 仍在參照節點時,被認定為「卸離」。卸離的 DOM 節點是記憶體流失的常見原因。本節說明如何使用開發人員工具的堆積分析器找出已卸離的節點。

以下是卸離 DOM 節點的簡單範例。

var detachedTree;

function create() {
  var ul = document.createElement('ul');
  for (var i = 0; i < 10; i++) {
    var li = document.createElement('li');
    ul.appendChild(li);
  }
  detachedTree = ul;
}

document.getElementById('create').addEventListener('click', create);

按一下程式碼中參照的按鈕,即可建立含有十個 li 子項的 ul 節點。這些節點已由程式碼參照,但不存在於 DOM 樹狀結構中,因此系統會卸離。

堆積快照是找出卸離節點的方法之一。顧名思義,堆積快照會顯示記憶體在快照建立點時,網頁 JS 物件和 DOM 節點之間的分配情形。

如要建立快照,請開啟開發人員工具並前往「Memory」面板,選取「Heap Snapshot」圓形按鈕,然後按下「Take Snapshot」按鈕。

拍攝堆積快照。

快照可能需要一段時間來處理和載入。完成後,請從左側面板選取 (名為「HEAP SNAPSHOTS」)。

在「類別篩選器」文字方塊中輸入 Detached,以搜尋卸離的 DOM 樹狀結構。

卸離的節點篩選

請展開顯示相關事故,並展開拆卸的樹木。

調查卸離的樹木

醒目顯示黃色的節點是透過 JavaScript 程式碼直接參照這些節點。醒目顯示的節點沒有直接參照。它們只是黃色節點的樹狀結構的一部分,因此才有效。一般而言,您應將重點放在黃色的節點上。修正程式碼,讓黃色節點的存留時間不超過所需時間,還能消除黃色節點樹狀結構中的紅色節點。

點擊黃色節點即可進一步調查。在「Objects」(物件) 窗格中,您可以查看參照該物件的程式碼更多資訊。舉例來說,在下方螢幕截圖中,您可以看到 detachedTree 變數參照節點。如要修正此特定的記憶體流失問題,您要研究使用 detachedTree 的程式碼,確保其會在不再需要時移除對節點的參照。

調查黃色節點

透過配置時間軸找出 JS 堆積記憶體流失問題

配置時間軸是一項工具,可協助您追蹤 JS 堆積中的記憶體流失情形。

如要展示配置時間軸,請考慮以下程式碼:

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

每次推送程式碼中參照的按鈕時,都會將一百萬個字元的字串新增至 x 陣列。

如要記錄配置時間軸,請開啟開發人員工具,前往「Profiles」(設定檔) 面板,選取「Record Allocation Timeline」(記錄配置時間軸) 圓形按鈕,按下「Start」(開始) 按鈕,執行您認為會造成記憶體流失的動作,然後在完成後按下「Stop record」(停止記錄) 按鈕 (「停止錄製」按鈕)。

錄製檔案時,請留意配置時間軸是否顯示任何藍色長條,如下方螢幕截圖所示。

新的分配

這些藍色長條代表新的記憶體配置。這些新的記憶體配置是可能發生記憶體流失的理想選擇。您可以縮放長條,篩選「建構函式」窗格,只顯示特定時間範圍內配置的物件。

縮放配置時間軸

展開物件並按一下該物件的值,即可在「Object」窗格中查看該物件的詳細資料。例如,在下方的螢幕截圖中,查看新分配的物件詳細資料後,即可看到該物件已分配給 Window 範圍中的 x 變數。

物件詳細資料

按照函式調查記憶體分配情形

使用「記憶體」面板中的「配置取樣」類型,查看不同 JavaScript 函式的記憶體配置。

記錄配置分析器

  1. 選取「Allocation Sampling」圓形按鈕。如果頁面上有工作站,您可以使用「Start」按鈕旁邊的下拉式選單,選取該工作站做為剖析目標。
  2. 按下「Start」按鈕。
  3. 在您要調查的網頁上執行操作。
  4. 完成所有動作後,按一下「Stop」按鈕。

開發人員工具會顯示各函式的記憶體配置分析。預設檢視畫面為「Heavy (Bottom Up)」,顯示在頂端分配最多記憶體的函式。

分配設定檔

查看經常收集的垃圾資訊集

如果您的網頁經常暫停,表示可能有垃圾收集問題。

您可以使用 Chrome 工作管理員或時間軸記憶體錄製內容,找出經常的垃圾收集事件。在工作管理員中,如果「記憶體」或「JavaScript 記憶體」值經常上升及下降,代表頻繁的垃圾集合。在時間軸記錄中,JS 堆積或節點數圖表經常上升和下降,代表頻繁的垃圾收集。

找出問題後,您就能使用配置時間軸記錄找出記憶體配置的位置,以及導致分配作業的函式。