這是我參與8月更文挑戰的第6天,活動詳情查看:8月更文挑戰javascript
上一篇中說到,不經意的內存泄露會致使程序變卡,甚至會出現頁面崩潰,下面經過例子來從瀏覽器的角度排查是否存在內存泄露,怎麼定位內存泄露。html
例子:java
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<button id="click">click</button>
<h1 id="content"></h1>
<script> let click = document.querySelector("#click"); let content = document.querySelector("#content") let arr = []; function testFun() { let test = new Array(1000).fill('1111') return function () { return test } } click.addEventListener("click", function () { arr.push(testFun()) arr.push(testFun()) content.innerHTML = arr.length }); </script>
</body>
</html>
複製代碼
這是一個不正當使用閉包構成的內存泄露的例子。 代碼中,爲頁面的button
綁定了一個點擊事件,每次點擊都執行兩次閉包函數,並把結果push
到全局的數組arr
中,因爲閉包函數執行結果也是一個函數,而且存在對原閉包函數內部數組test
的引用,因此arr數組中的每一項元素都使得引用的閉包內部test
數組對象沒有辦法回收,arr
數組有多少元素,也就存在多少次閉包引用,咱們點擊的越多,push
就越多,內存就消耗越大,頁面也會愈來愈卡。數組
這是咱們知道問題的狀況下,對內存泄露的排查,當項目龐大的時候咱們就無法直接定位到具體代碼了,這時候就須要藉助瀏覽器控制檯(Chrome Devtool
)了。瀏覽器
首先打開瀏覽器的無痕模式,打開程序控制臺:markdown
而後找到Performance,他是用來監控性能指標的工具,能夠記錄分析在網站的生命週期內發的各種事件:閉包
接下來開始操做,在開始以前必定要確認勾選了 Memory
(序號5)選項 ,這樣咱們才能夠看到內存相關的分析。app
點擊開始錄製(序號 1)進入錄製狀態,隨後先清理一下GC(垃圾回收),也就是最右邊的垃圾桶(序號6)。函數
而後一直點擊按鈕50次,頁面數值應該是100,再點擊一下垃圾桶,手動觸發一次GC(垃圾回收),再點擊150次,而後中止錄製。工具
咱們能夠明顯看到內存數據是一個不斷上漲的趨勢,並且即便咱們在50次的時候手動垃圾回收了一次,清理後的內存也沒有少不少。
在這段代碼中,咱們能夠很快的知道是點擊按鈕的操做出現了內存泄露,但真實項目中,項目過於龐大,操做過多的狀況下,是不容易很快定位到具體問題的。這時候須要藉助Memory
,它能夠記錄JS中CPU執行時間細節,顯示JS對象和相關的DOM節點的內存消耗內存的分配細節等。
Memory
中的Heap Profiling
能夠記錄當前的堆內存 heap
的快照,並生成對象的描述文件,該描述文件給出了當下 JS 運行所用的全部對象,以及這些對象所佔用的內存大小、引用的層級關係等等,用它就能夠定位出引發問題的具體緣由以及位置。
咱們點擊左邊的生成快照,就生成了Snapshot 1,它表明了剛剛這一刻的內存狀態。
快照這邊有一個下拉框:
默認顯示的是Summary
,下面的信息就表明快照生成的一瞬間,內存中存了什麼,佔用內存的信息等。
Summary
中數據表格的信息表示什麼:
咱們這時候選擇第三個直接進行對比:
在這裏咱們點開能夠看到,代碼在19行存在內存泄露,同時看Array,也表明着全局變量要是在頁面關閉前沒清理,就會一直存在內存中。
這樣咱們就成功了定位到了內存泄露的緣由。 在實際項目中,問題可能會更加複雜,咱們要根據具體場景選擇解決方案,解決以後重複上面排查流程就行排查。
在這裏順便了解一下什麼是內存三大件,也就是內存方面主要的三個問題:
內存泄漏
咱們說好久了,對象已經再也不使用但沒有被回收,內存沒有被釋放,即內存泄漏,那想要避免就避免讓無用數據還存在引用關係,也就是多注意咱們上面說的常見的幾種內存泄漏的狀況。
內存膨脹
即在短期內內存佔用極速上升到達一個峯值,想要避免須要使用技術手段減小對內存的佔用。
頻繁 GC
就是 GC(垃圾回收) 執行的特別頻繁,通常出如今頻繁使用大的臨時變量致使新生代空間被裝滿的速度極快,而每次新生代裝滿時就會觸發 GC,頻繁 GC 一樣會致使頁面卡頓,想要避免的話就不要搞太多的臨時變量,由於臨時變量不用了就會被回收,這和咱們內存泄漏中說避免使用全局變量衝突,其實,只要把握好其中的度,不太過度就 沒事。