Chrome開發者工具詳解(4)-Profiles面板

Chrome開發者工具詳解(4)-Profiles面板

若是上篇中的Timeline面板所提供的信息不能知足你的要求,你可使用Profiles面板,利用這個面板你能夠追蹤網頁程序的內存泄漏問題,進一步提高程序的JavaScript執行性能javascript

概述

當前使用的Chrome最新版爲54.0.2840.71,這個版本的Profiles面板比以前提供的功能更多也更強大,下面是該面板所包含的功能點:java

  • Record JavaScript CPU Profile 用於分析網頁上的JavaScript函數在執行過程當中的CPU消耗信息。
  • Take Heap Snapshot 建立堆快照用來顯示網頁上的JS對象和相關的DOM節點的內存分佈狀況。
  • Record Allocation Timeline 從整個Heap角度記錄內存的分配信息的時間軸信息,利用這個能夠實現隔離內存泄漏問題。
  • Record Allocation Profile 從JS函數角度記錄內存的分配信息。

Record JavaScript CPU Profile簡介

經過選擇Record JavaScript CPU Profile,而後點擊Start,結合你所要分析的具體場景,你能夠從新加載網頁,或者在網頁上進行交互,甚至什麼都不操做。最後點擊Stop,完成記錄操做。正則表達式

有三種不一樣的視圖可供選擇:chrome

  • Chart 按時間前後順序顯示的火焰圖。

  • Heavy(Bottom Up) (自底向上)根據對性能的消耗影響列出全部的函數,並能夠查看該函數的調用路徑。

  • Tree(Top Down) (自頂向下) 從調用棧的頂端(最初調用的位置)開始,顯示調用結構的整體的樹狀圖狀況。

咱們以Chart視圖爲例分析一下JS的執行的性能狀況:數組

該視圖會以時間順序展現CPU的性能狀況,視圖主要分紅兩塊:瀏覽器

  • Overview 整個錄製結果的鳥瞰圖(概覽),柱形條的高度對應了調用堆棧的深度,也就是說柱形條高度越高,調用堆棧的深度越深。
  • Call Stacks 在錄製過程當中被調用的函數的深刻分析視圖(調用堆棧),橫軸表示時間,縱軸表示調用棧,自上而下的表示函數的調用狀況。也就是說上面的函數調用在它下面的函數。

視圖中的函數顏色不一樣於其它的面板,這裏面的函數顏色標記是隨機顯示的。然而相同的函數調用顏色標記是相同的。緩存

其中縱軸表示的函數調用堆棧高度僅僅函數的調用嵌套層次比較深,不表示其重要性很高,可是橫軸上一個很寬的柱形條則意味着函數的調用須要一個很長的時間去完成,那麼你就考慮去作一些優化操做,具體能夠參見網絡性能優化方案及裏面的相關參考文檔。性能優化

將鼠標移到Call Stacks中的函數上能夠顯示函數的名稱和時間相關的數據,會提供以下信息:網絡

  • Name 函數名稱
  • Self time 函數的本次調用運行的時間,僅僅包含該函數自己的運行時間,不包含它所調用的子函數的時間。
  • Total time 函數的本次調用運行的總時間,包含它所調用的子函數的運行時間。
  • URL 函數定義在文件中所在的位置,其格式爲file.js:100,表示函數在file.js文件中的第100行。
  • Aggregated self time 在此次的錄製過程當中函數調用運行的總時間,不包含它所調用的子函數的時間。
  • Aggregated total time 在此次的錄製過程當中全部的函數調用運行的總時間,包含它所調用的子函數的時間。
  • Not optimized 若是優化器檢測到該函數有潛在的優化空間,那麼該函數會被列在這裏。

Take Heap Snapshot簡介

經過建立堆快照能夠查看建立快照時網頁上的JS對象和DOM節點的內存分佈狀況。利用該工具你能夠建立JS的堆快照、內存分析圖、對比堆快照以及定位內存泄漏問題。選中Take Heap Snapshot,點擊Take Snapshot按鈕便可獲取快照,在每一次獲取快照前都會自動執行垃圾回收操做。閉包

快照最初會存儲在渲染進程的內存之中,當咱們點擊建立快照按鈕來查看時纔會被傳輸到DevTools中,當快照被加載到DevTools裏面並通過解析以後,在快照標題下方的文字顯示是數字就是可訪問到的JS對象總的大小。

堆快照提供了不一樣的視角來進行查看:

  • Summary 該視圖按照構造函數進行分組,用它能夠捕獲對象和它們使用的內存狀況,對於跟蹤定位DOM節點的內存泄漏特別有用。
  • Comparison 對比兩個快照的差異,用它能夠對比某個操做先後的內存快照。分析操做先後的內存釋放狀況以及它的引用計數,便於你確認內存是否存在泄漏以及形成的緣由。
  • Containment 該視圖能夠探測堆的具體內容,它提供了一個更適合的視圖來查看對象結構,有助於分析對象的引用狀況,使用它能夠分析閉包和進行更深層次的對象分析。
  • Statistics 統計視圖。

Summary視圖

該視圖會顯示全部的對象信息,點擊其中的一個對象進行展開可查看更詳細的實例信息。鼠標移動到某個對象上會顯示該對象實例的詳情信息。

圖中的各列的具體含義以下:

  • Constructor 顯示全部的構造函數,點擊每個構造函數能夠查看由該構造函數建立的全部對象。
  • Distance 顯示經過最短的節點路徑到根節點的距離。
  • Objects Count 顯示對象的個數和百分比。
  • Shallow size 顯示由特定的構造函數建立的全部對象的自己的內存總數。
  • Retained size 顯示由該對象及其它所引用的對象的總的內存總數。

Shallow sizeRetained size的區別?Shallow size是對象自己佔用內存的大小,不包含它所引用的對象。Retained size是該對象自己的Shallow size,加上能從該對象直接或者間接訪問到對象的Shallow size之和。也就是說Retained size是該對象被GC以後所能回收到內存的總和。

在展開構造函數,則會列出該函數相關的全部對象實例,能夠查看該對象的Shallow size和Retained size,在@符號後面的數字是該對象的惟一標識ID。

其中黃色的對象表示在它被某個JS所引用,而紅色的對象表示由黃色背景色引用被分離開出的節點。

這些構造函數都表明什麼含義呢?

  • (global property) 全局對象(好比window)和經過它引用的對象之間的中間對象,若是一個對象是由Person構造函數生成並被全局對象所引用,那麼它們的引用路徑關係就像這樣[global] > (global property) > Person。這跟常規的對象之間直接引用相比,採用中間對象主要是考慮性能的緣由。全局對象的改變是很頻繁的,而非全局變量的屬性訪問最優化方案對全局變量是不適用的。
  • (roots) 它們能夠是由引擎本身的目標建立的一些引用,這個引擎能夠緩存引用的對象,但全部的這些引用都是弱引用,它們不會阻止引用對象被回收。
  • (closure) 一些函數閉包中的一組對象的引用。
  • (array, string, number, regexp) 一系屬性引用了數組(Array),字符串(String),數字(Number)或正則表達式的對象類型。
  • HTMLDivElement, HTMLAnchorElement, DocumentFragment等 你的代碼中對元素(elements)的引用或者指定的document對象的引用。

Comparison視圖

經過比較多個快照之間的差別來找出內存泄露的對象,爲了驗證某個程序的操做不會引發內存泄露(一般會執行一個操做後再執行一個對應的相反操做,好比打開一個文檔後再關閉它,應該是沒有產生內存泄露問題的),你能夠執行以下步驟:

  1. 在執行一個操做以前拍一個快照。
  2. 執行一個操做,經過你認爲可能會引發內存泄露的一次頁面交互操做。
  3. 執行一個相反的操做。
  4. 拍第二個快照,切換到Comparison視圖,並與第一個快照進行對比。

切換到Comparison視圖以後,就能夠看到兩個不一樣的快照之間的差異。

Containment視圖

該視圖本質上就是應用程序的對象結構的「鳥瞰圖」,容許你去深刻分析函數的閉包,瞭解應用程序底層的內存使用狀況。

這個視圖提供了多個入口:

  • DOMWindow objects DOMWindow對象,即JS代碼全局對象。
  • Native objects 瀏覽器原生對象,好比DOM節點,CSS規則。

閉包小建議: 在快照的分析中命名函數的閉包相比匿名函數的閉包更容易區分。

Google上提供的例子和圖以下:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // 匿名函數
    return largeStr;
  };

  return lC;
}
function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // 命名函數
    return largeStr;
  };

  return lC;
}

Statistics視圖

該視圖是堆快照的總的分佈統計狀況,這個直接上圖就能夠了:

內存泄露示例

仍是把Google提供的內存泄露的小例子貼出來:

DOM內存泄露可能比你想象的要大,考慮一下下面的例子-何時#tree節點被釋放掉?

var select = document.querySelector;
  var treeRef = select("#tree");
  var leafRef = select("#leaf");
  var body = select("body");

  body.removeChild(treeRef);

  //因爲treeRef #tree不能被釋放
  treeRef = null;

  //因爲leafRef的間接引用 #tree仍是不能被釋放

  leafRef = null;
  //如今沒有被引用,#tree這個時候才能夠被釋放了

#leaf節點保持着對它的父節點(parentNode)的引用,這樣一直遞歸引用了#tree節點,因此只有當leafRef被設置成null後,#tree下面的整個樹節點纔有可能被垃圾回收器回收。

Record Allocation Timeline簡介

該工具是能夠幫助你追蹤JS堆裏面的內存泄漏的另外一大利器。

選中Record Allocation Timeline按鈕,點擊Start按鈕以後,執行你認爲可能會引發內存泄漏的操做,操做以後點擊左上角的中止按鈕便可。你能夠在藍色豎線上經過縮放來過濾構造器窗格來僅僅顯示在指定的時間幀內的被分配的對象。

錄製過程當中,在時間線上會出現一些藍色豎條,這些藍色豎條表明一個新的內存分配,這個新的內存分配均可以會有潛在的內存泄露問題。

經過展開對象並點擊它的值則能夠在Object窗格中查看更多新分配的對象細節。

Record Allocation Profile簡介

從JS函數角度記錄並查看內存的分配信息。點擊Start按鈕,執行你想要去深刻分析的頁面操做,當你完成你的操做後點擊Stop按鈕。而後會顯示一個按JS函數進行內存分配的分解圖,默認的視圖是Heavy (Bottom Up),該視圖會把最消耗內存的函數顯示在最頂端。

下圖是切換到Chart視圖時具體的界面,點擊任意函數跳轉到Sources面板能夠查看具體的函數信息。

參考文檔

我的博客

個人我的博客

相關文章
相關標籤/搜索