自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如何排查網(wǎng)頁(yè)在哪里發(fā)生了內(nèi)存泄漏?

開(kāi)發(fā) 前端
今天我們來(lái)學(xué)習(xí)用 Devtool 的 Performance 和 Memory 工具來(lái)找出網(wǎng)頁(yè)哪里發(fā)生了內(nèi)存泄漏。

大家好,我是前端西瓜哥。

今天我們來(lái)學(xué)習(xí)用 devtool 的 Performance 和 Memory 工具來(lái)找出網(wǎng)頁(yè)哪里發(fā)生了內(nèi)存泄漏。

Performace 面板

首先我們打開(kāi)瀏覽器的 devtool,選擇 Performance(性能)面板,然后將 Memory 選項(xiàng)勾選上。不勾選的話,就不會(huì)記錄內(nèi)存使用情況,內(nèi)存泄漏分析就無(wú)從說(shuō)起了。

然后進(jìn)行性能數(shù)據(jù)收集:

  1. 點(diǎn)擊左上角的 “錄制” 按鈕(一個(gè)灰色的圓形),或者點(diǎn)它旁邊的 “刷新” 按鈕,會(huì)重新加載頁(yè)面并開(kāi)始記錄,這樣就不用手動(dòng)刷新然后手忙腳亂地點(diǎn)錄制按鈕了;
  2. 在頁(yè)面上執(zhí)行可能發(fā)生內(nèi)存泄漏的操作,比如打開(kāi)一個(gè)彈窗,然后再關(guān)閉;
  3. 差不多了就再點(diǎn)擊 “錄制” 按鈕,結(jié)束錄制,然后出現(xiàn)下面圖片的結(jié)果。

圖片

查看內(nèi)存指標(biāo)

看看內(nèi)存的使用情況。有這么幾步:

  1. 選中要分析的范圍;
  2. 選中 Main(主線程)。只有選中的話,內(nèi)存圖表才能顯示主線程對(duì)應(yīng)的信息;
  3. 查看內(nèi)存圖表的指標(biāo)。

圖片

內(nèi)存圖表是一些折線圖,記錄了內(nèi)存指標(biāo)隨時(shí)間發(fā)生的變化。這些內(nèi)存指標(biāo)有:JS 堆內(nèi)存、Document 數(shù)、節(jié)點(diǎn)數(shù)、綁定監(jiān)聽(tīng)器數(shù)量、GPU 內(nèi)存。

點(diǎn)擊它們可顯示或隱藏對(duì)應(yīng)的折線圖。

對(duì)于  JS Heap(11.9MB - 25.6MB) ,它表示的是在當(dāng)前時(shí)間范圍內(nèi),JS 堆內(nèi)存最小值為 11.9 MB,最大為 25.6 MB。

將光標(biāo)懸停在折線圖上,可以看到對(duì)應(yīng)的值:

圖片

查看內(nèi)存下限的變化

內(nèi)存會(huì)增長(zhǎng)是正常的現(xiàn)象。比如我們調(diào)用函數(shù),會(huì)創(chuàng)建一些臨時(shí)變量,導(dǎo)致內(nèi)存升高。函數(shù)執(zhí)行完,這些變量就沒(méi)用了,但不會(huì)馬上回收,而是會(huì)在適當(dāng)?shù)臅r(shí)機(jī)進(jìn)行內(nèi)存回收,將內(nèi)存再降下去。

臨時(shí)分配的短命內(nèi)存我們并不關(guān)心,我們更關(guān)注的是一些常駐的內(nèi)存,對(duì)應(yīng)的要看的是 內(nèi)存下限的變化。

圖片

如果內(nèi)存下限不斷上升,說(shuō)明常駐內(nèi)存變大了。大多數(shù)情況下是正常的,比如:

  1. 調(diào)用函數(shù),將函數(shù)返回的結(jié)果進(jìn)行緩存;
  2. 創(chuàng)建新的組件。

也可能是內(nèi)存泄漏了。

當(dāng)懷疑是內(nèi)存泄漏時(shí),我們就可以使用 Memory 面板記錄快照,做進(jìn)一步的排查。

Memory 面板

打開(kāi) Memory 面板,點(diǎn)擊左上角的 “錄制按鈕”,生成當(dāng)前時(shí)刻的堆內(nèi)存快照。然后通過(guò)快照了解 JS 對(duì)象的內(nèi)存分布

圖片

Summary View

快照結(jié)果默認(rèn)會(huì)展示為 概要視圖(Summary View)。

圖片

這個(gè)表格的表格項(xiàng)是基于構(gòu)造函數(shù)進(jìn)行歸類的。可以看到有不少原生的構(gòu)造函數(shù),還有一堆閉包。

每個(gè)項(xiàng)有以下幾個(gè)屬性:

  • Constructor:構(gòu)造函數(shù)。對(duì)于沒(méi)有構(gòu)造函數(shù)的字面量,用類似(string)? 、(array) 的表示。
  • Distance:到根節(jié)點(diǎn)的最短路徑。
  • Shallow Size:自己占用的內(nèi)存大小,不包括它引入的其他對(duì)象內(nèi)存,單位為字節(jié)。
  • Retained Size:對(duì)象自己以及它引用的對(duì)象的內(nèi)存,單位也是字節(jié)。
  • Object Count:對(duì)象數(shù)量,就是 Constructor 名旁邊那個(gè)數(shù)字。

上面是默認(rèn)的 Summary View 視圖。

除了它,我們還有其他的視圖,可以像下面這樣進(jìn)行視圖類型的切換。

圖片

Comparison View

比較視圖(Comparison View)則是用來(lái)比較兩個(gè)快照的變化。

圖片

這里我選中了快照 3,然后將對(duì)比快照設(shè)置為 快照 1。

這個(gè)表格表示從快照 1 變成快照 3 發(fā)生的變化。沒(méi)有發(fā)生變化的項(xiàng)不會(huì)進(jìn)行展示。

字段有:

  • Constructor:構(gòu)造函數(shù)。
  • #New:新增的對(duì)象數(shù)量。
  • #Deleted:刪除的對(duì)象數(shù)量。
  • #Delta:總體上的對(duì)象變化數(shù)量。
  • Alloc.Size:分配的總內(nèi)存。
  • Freed Size:釋放了多少內(nèi)存。
  • Size Delta:總體上的內(nèi)存變化。

Containment View

該視圖可以讓我們從根節(jié)點(diǎn)為起點(diǎn),往下去查看各種對(duì)象占用的內(nèi)存,以及被創(chuàng)建的代碼位置等信息。

圖片

字段:

  • Object:普通對(duì)象或者 DOM 節(jié)點(diǎn):
  • Distance:到根節(jié)點(diǎn)的距離。
  • Shallow Size:對(duì)象大小,不計(jì)算引用的對(duì)象。
  • Retained Size:對(duì)象大小,但其引用的對(duì)象大小也計(jì)算在內(nèi)。

Statistics View

圓環(huán)統(tǒng)計(jì)表。

各種內(nèi)存類型的占總內(nèi)存的百分比情況。

圖片

使用 Memory 面板注意事項(xiàng)

盡量減少干擾項(xiàng)的影響力。

  1. 分辨正常的內(nèi)存變化會(huì)的干擾。
  2. 注意開(kāi)發(fā)環(huán)境的打包器熱加載邏輯等的影響。
  3. 生成環(huán)境的代碼是混淆過(guò)的,一些構(gòu)造器名字很奇怪,如果可以的話,本地打包一份沒(méi)經(jīng)過(guò)混淆過(guò)的代碼做 debug?;蛘咭部梢?hover 看看對(duì)象結(jié)構(gòu)猜測(cè)對(duì)應(yīng)構(gòu)造器,但效率不高。
  4. 不要有瀏覽器插件,它們也占用和影響內(nèi)存,可以用無(wú)痕瀏覽器。

常見(jiàn)內(nèi)存泄漏原因和排查

忘記及時(shí)取消監(jiān)聽(tīng)器綁定

新手老鳥(niǎo)都容易犯的錯(cuò)誤,就是 忘記及時(shí)取消監(jiān)聽(tīng)器綁定。它會(huì)導(dǎo)致:

  1. 監(jiān)聽(tīng)器函數(shù)中的對(duì)象遲遲不能釋放,比如非常大的組件實(shí)例。
  2. 綁定大量無(wú)用的監(jiān)聽(tīng)器函數(shù)。

怎么排查?

如果監(jiān)聽(tīng)器是綁定到 DOM 中,我們可以不斷執(zhí)行可以看 Listener 數(shù)量的變化。

我寫(xiě)了個(gè)彈窗組件,它會(huì)在掛載時(shí)給 document.body 注冊(cè)一個(gè)函數(shù),然后這個(gè)函數(shù)會(huì)用到這個(gè)組件下的變量。但銷毀時(shí)不取消注冊(cè)。

打開(kāi) Performance 面板,錄制,然后不停打開(kāi)和關(guān)閉彈窗,然后結(jié)束錄制。我們就能看這個(gè) Listeners 的數(shù)量的變化,不斷地變高那就是忘了。

圖片

也可以看看 Memoery 面板中 Comparison View 的快照對(duì)比中,EventListener 數(shù)量的變化:

圖片

具體是哪個(gè),可以看 EventListener 下的最后幾個(gè)對(duì)象。

圖片

點(diǎn)擊這個(gè)藍(lán)色的鏈接,就能跳到對(duì)應(yīng)的代碼位置:

圖片

此外,還可以用 Chrome 控制臺(tái)提供的 getEventListeners(element) 方法,它會(huì)返回一個(gè)元素事件綁定的函數(shù)有哪些。這個(gè)方法不是標(biāo)準(zhǔn)方法,是 Chrome 自帶的工具方法,只能在控制臺(tái)上用。我們可以寫(xiě)個(gè)方法,從根節(jié)點(diǎn)往下找,找出綁定函數(shù)數(shù)量最多的節(jié)點(diǎn),這個(gè)節(jié)點(diǎn)多得離譜那就大概率是忘了解綁。

如果不是 DOM 上的監(jiān)聽(tīng)器,比如發(fā)布訂閱庫(kù)的事件集合,那就要看構(gòu)造器對(duì)應(yīng)對(duì)象數(shù)量的變化了。

閉包

閉包就是拿到函數(shù) A 內(nèi)的另一個(gè)函數(shù) B,函數(shù) B 會(huì)捕獲到函數(shù) A 作用域中的變量。

這個(gè)就導(dǎo)致了對(duì)一些對(duì)象的隱式引用,比如一個(gè) DOM 元素。我們需要在不需要使用時(shí)將其設(shè)置為 null。

我們可以看看有沒(méi)有什么 Detached 的元素。Detached 表示不在當(dāng)前文檔樹(shù)上,如果持續(xù)增多,可能發(fā)生了內(nèi)存泄漏。

圖片

說(shuō)真的閉包是一個(gè)正常的特性,沒(méi)理由和內(nèi)存泄漏有關(guān)才是。

函數(shù) B 被持有不銷毀,自然它捕獲的函數(shù) A 中的變量就不能銷毀,和對(duì)象里有一些屬性,這些屬性不能銷毀沒(méi)啥區(qū)別。函數(shù) B 銷毀了,對(duì)應(yīng)的變量自然也就回收了。

有空我再研究下寫(xiě)篇專題。

console

“你到底都打印了些什么???”

還有個(gè)比較常見(jiàn)的就是,在開(kāi)發(fā)的時(shí)候用 console 打印一些對(duì)象,合并到主分支又忘記去掉。這些對(duì)象是不會(huì)被回收的,因?yàn)殚_(kāi)發(fā)者可能會(huì)去控制臺(tái)看看這些對(duì)象的內(nèi)容。這在打印大量大對(duì)象時(shí)會(huì)出性能問(wèn)題。

排查方法很簡(jiǎn)單,去看 DevTool 的控制臺(tái)輸出了什么內(nèi)容,看看有沒(méi)有大對(duì)象。

一些有助于 debug 的 console 是有必要的,但不要濫用。

集合類型的緩存爆炸

我們經(jīng)常用對(duì)象、數(shù)組、Map、Set 等集合類型,去做數(shù)據(jù)的緩存。

當(dāng)緩存大量對(duì)象時(shí),會(huì)占用大量的內(nèi)存,但其中有不少內(nèi)容是不需要用的。對(duì)于前端來(lái)說(shuō),內(nèi)存不像后端那樣純金寸土,動(dòng)不動(dòng)就是大批量數(shù)據(jù)要處理,緩存使用起來(lái)挺隨意的。

對(duì)于緩存問(wèn)題,還要要有點(diǎn)意識(shí),我們可以:

  1. 使用 LRU 算法,將最久沒(méi)使用的緩存移除,控制緩存數(shù)量;
  2. 設(shè)置緩存過(guò)期時(shí)間;
  3. 對(duì)于臨時(shí)緩存,考慮使用  WeakMap 和 WeakSet,它們會(huì)在 GC 時(shí)強(qiáng)制回收;

這些就沒(méi)啥好分析的,就看看內(nèi)存下限變化,某些對(duì)象是否變大變多了。

結(jié)尾

今天帶大家簡(jiǎn)單入門(mén)了 devtool 提供的內(nèi)存分析工具,但光說(shuō)不練假把式,還是要多多實(shí)戰(zhàn)。

責(zé)任編輯:姜華 來(lái)源: 前端西瓜哥
相關(guān)推薦

2023-12-18 10:45:23

內(nèi)存泄漏計(jì)算機(jī)服務(wù)器

2021-01-18 08:23:23

內(nèi)存時(shí)底層CPU

2019-09-16 17:16:29

Hadoop數(shù)據(jù)湖數(shù)據(jù)結(jié)構(gòu)

2021-08-09 09:54:37

內(nèi)存泄漏JS 阿里云

2021-08-05 15:28:22

JS內(nèi)存泄漏

2019-11-12 14:41:41

Redis程序員Linux

2020-11-02 09:48:35

C++泄漏代碼

2019-12-17 10:01:40

開(kāi)發(fā)技能代碼

2024-11-21 09:30:38

內(nèi)存泄漏CPU

2024-11-22 09:40:18

Visual內(nèi)存泄漏內(nèi)存

2020-08-17 12:47:07

Mozilla裁員瀏覽器

2013-12-17 15:46:04

iOS開(kāi)發(fā)iOS 內(nèi)存泄漏

2022-02-08 17:17:27

內(nèi)存泄漏排查

2021-01-18 14:04:49

java監(jiān)控操作

2022-05-26 09:51:50

JavaScrip內(nèi)存泄漏

2011-08-15 10:16:55

內(nèi)存泄露

2010-02-07 09:00:29

AndroidLinux Kerne

2019-08-26 09:35:25

命令ping抓包

2024-01-30 10:12:00

Java內(nèi)存泄漏

2022-06-15 16:04:13

Java編程語(yǔ)言
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)