Chrome 開發工具之 Memory

開發過程當中不免會遇到內存問題,emmm... 本文主要記錄一下Chrome排查內存問題的面板,官網也有,但有些說明和例子跟不上新的版本了,也不夠詳細...
 
!!! 多圖預警!!! 
 
簡單的內存信息列表
 
若是隻想查看當前瀏覽器的各個 tab 正在使用的內存量,則在 Setting - More Tools - Task Manager 便可。效果以下圖:
 
 
那個列表裏的可勾選項,沒看錯,是對於可選的信息數據列。
 
那個 End Process 按鈕,沒看錯,選擇一項後,能夠在瀏覽器所起的任務列表裏關閉改任務(任務能夠是打開頁面的 tab、Chrome 自身一些項目及擴展插件...爲何不是按鈕上寫的 process,由於這些任務裏面只有部分是在機器進程列表裏列出存在的,強行嚴格 ~ToT~ )
  
須要看內存的實時變化過程,能夠在 Chrome - Performance 面板查看時間軸上內存變化狀況,其中會有 `js Heap` 記錄的選項,詳情參考 Chrome 開發工具之 Timeline/Performance
 
Memory 面板初始
 
若是想要看更多的內存信息快照,則須要打開 Chrome 瀏覽器的開發者工具中的 Memory 面板了,下面就簡單介紹一下該面板的使用。
它大概是長這樣:
 

上面有三個按鈕:javascript

  • Heap snapshot - 用以打印堆快照,堆快照文件顯示頁面的 javascript 對象和相關 DOM 節點之間的內存分配
  • Allocation instrumentation on timeline - 在時間軸上記錄內存信息,隨着時間變化記錄內存信息。
  • Allocation sampling - 內存信息採樣,使用採樣的方法記錄內存分配。此配置文件類型具備最小的性能開銷,可用於長時間運行的操做。它提供了由 javascript 執行堆棧細分的良好近似值分配。
 
各自舉些例子吧,方便理解
 
Heap snapshot
 
給個 html,裏面只有一句 js 代碼 var _____testArray_____ = [ {value: 'hello'} ]; ,打個堆棧看看:
 
 
右上那塊區域,從左到右有三個操做:查看方式、對象歸類的篩選、對象選擇。
 
左邊有 `Summary` 字樣的那個,能夠選擇查看內存快照的方式,可選方式以下:
  • Summary - 能夠顯示按構造函數名稱分組的對象。使用此視圖能夠根據按構造函數名稱分組的類型深刻了解對象(及其內存使用),適用於跟蹤 DOM 泄漏。
  • Comparison - 能夠顯示兩個快照之間的不一樣。使用此視圖能夠比較兩個(或多個)內存快照在某個操做先後的差別。檢查已釋放內存的變化和參考計數,能夠確認是否存在內存泄漏及其緣由。
  • Containment - 此視圖提供了一種對象結構視圖來分析內存使用,由頂級對象做爲入口。
  • Statistic - 內存使用餅狀的統計圖。
附上 Comparison 效果,大體以下:
代碼:
var _____testArray_____ = [{ value: 'hello' }]

function someTodo() {
  _____testArray_____.push({
    value: ':::::::::'
  })
}

document.querySelector('#btn').addEventListener('click', someTodo, false)
 
點擊按鈕後,數組中 push 了新的一項對象
圖(array 那塊列表展開就看不到下面列表了,就沒展開):
 
附上 Containment 視圖,它的排列稍微有些不一樣,大體以下:

 

入口有:
  • DOMWindow - 是被視爲 JavaScript 代碼 "全局" 對象的對象。
  • GC - VM 的垃圾使用的實際 GC 根。GC 根能夠由內置對象映射、符號表、VM 線程堆棧、編譯緩存、句柄做用域和全局句柄組成。
  • 原生對象 - 是 "推送" 至 JavaScript 虛擬機內以容許自動化的瀏覽器對象,例如 DOM 節點和 CSS 規則。
 
中間的 `Class filter` 只可以按照列出來的 Constructor 值進行篩選。
 
右邊的 `All objects` 可以選擇查看哪些階段的對象、如 "Objects allocated before Snapshot1"、"Objects allocated between Snapshot1 and Snapshot2"

右中那塊區域顯示的內存快照信息,能夠在各個數據上右鍵選擇一些操做( `Reveal in Summary view` ),各個字段表明信息以下:
  • Contructor - 表示使用此構造函數建立的全部對象
  • Distance - 顯示使用節點最短簡單路徑時距根節點的距離
  • Shallow Size - 顯示經過特定構造函數建立的全部對象淺層大小的總和。淺層大小是指對象自身佔用的內存大小(通常來講,數組和字符串的淺層大小比較大)
  • Retained Size - 顯示同一組對象中最大的保留大小。某個對象刪除後(其依賴項再也不可到達)能夠釋放的內存大小稱爲保留大小。
  • #New - Comparison 特有 - 新增項
  • #Deleted - Comparison 特有 - 刪除項
  • #Delta - Comparison 特有 - 增量
  • Alloc. Size - Comparison 特有 - 內存分配大小
  • Freed Size - Comparison 特有 - 釋放大小
  • Size Delta - Comparison 特有 - 內存增量

右下那塊區域顯示的是被選中對象的詳細信息,如上面圖片的內容同樣同樣的...能夠在各個數據上右鍵選擇一些操做( `Reveal in Summary view` )。

注意:圖中最最下面那塊最有用,就是搜索,ctrl/command + f 喚出 ~

最後,根據上面的圖來分析一下上面代碼產生的效果,根據 js 的類型和引用的關係來分析,變量 _____testArray_____ 在列表中的狀況是:
  • 基礎類型 string 值爲 hello ,內存標記是 string@353953,這個 string 值存在於 Object @362113 對象上的 value 屬性上;
  • Object @362113 在 Object 列表裏,在 Array @356493 的索引 0 位置存在該對象的引用;
  • Array @356493 在 Window / @353829 對象上存在引用,屬性名爲"___testArray___";
  • Window / @353829 是個 Windows 對象,在 Windows 列表裏。 
"hello" -> 在(string)列表裏 -> string@353953 -> value in Object @362113

    Object  -> 在 Object 列表裏 -> [0] in Array @356493

        Array -> 在(array)列表裏 -> _____testArray_____ in Window / @353829

                Windows ->  在 Windows 列表裏 -> Window / @353829
 
Allocation instrumentation on timeline
 
看完靜態的快照,再來看看動態的。
代碼以下:
var _____testArray_____ = [{ value: 'hello' }]
var count = 1

function someTodo() {
  // 每次點擊 字符串長度都以上一次爲基礎增長到5倍,拉大差別突出效果,而且以後在字符串頭部加上count值作區分
  count *= 5
  var str = new Array(count * 10).join(':')
  _____testArray_____.push({
    value: count + str
  })
}

document.querySelector('#btn').addEventListener('click', someTodo, false)
 
選擇 Allocation instrumentation on timeline 點擊開始記錄的按鈕,而後獲得如圖所示:
 

 

每條線的高度與最近分配的對象大小對應,豎線的顏色表示這些對象是否仍然顯示在最終的堆快照中。藍色豎線表示在時間線最後對象仍然顯示,灰色豎線表示對象已在時間線期間分配,但曾對其進行過垃圾回收。(這圖中不是很明顯,放大 devtool 面板後,圖中的藍色線頂部是有部分是灰色的...)
 
能夠選擇時間範圍,查看該時間範圍內的內存變化狀況,如上圖 5 次變化的狀況分別是:
# 前面的數字表明本次記錄索引,點擊了5次

# 0  Shallow Size : 112
Constructor         Distance   Shallow Size    Retained Size
- - - - - - - - - - - - - - - - - - - - - - - - -  - - - - - - - - - - -
(array)×9                3      5008  0%         5008  0%
(system)×60              3      2416  0%         2640  0%
(closure)×1              3      4768  0%         2928  0%
Object×3                 3      144   0%         768   0%
MouseEvent×3             4      112   0%         7200  0%
(string)×2               5      96    0%         96    0%
(concatenated string)×2  4      64    0%         160   0%
Event                    5      56    0%         2040  0%
UIEvent                  5      32    0%         648   0%

# 1
(string)×2               5      296   0%         296   0%
(concatenated string)×2  4      64    0%         360   0%
Object                   3      32    0%         392   0%

# 2
(string)×2               5      1296  0%         1296  0%
(concatenated string)×2  4      64    0%         1360  0%
Object                   3      32    0%         1392  0%

# 3
(string)×2               5      6296  0%         6296  0%
(concatenated string)×2  4      64    0%         6360  0%
Object                   3      32    0%         6392  0%

# 4
(string)×2               5      31296 0%         31296 0%
(array)                  4      80    0%         80    0%
(concatenated string)×2  4      64    0%         31360 0%
(system)                 4      32    0%         32    0%
Object                   3      32    0%         31392 0%

 

當勾選 Record allocation stacks 框後,還能夠在 Allocation stack 面板裏打印出調用堆棧。
如上面代碼的效果:

 

Allocation sampling
 
這個功能根據名稱和說明,不是很看得懂是什麼... 可是,仍是經過一些案例給出了效果圖,以下:

 

根據給出的圖,能夠看出這塊的功能應該是:哪些函數影響了內存的分配,而且該函數所耗內存在內存分配中佔比多少。
圖中函數能夠直接點擊跳轉到函數定義的文件和位置。

記錄完畢,撒花...
相關文章
相關標籤/搜索