這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
很多前端都喜歡用 console.log 除錯,先不談除錯效率怎么樣,首先 console.log 有個致命的問題:會導致記憶體泄漏,
為什么這么說呢?
用 Performance 和 Memory 工具分析下就知道了,
我們準備這樣一段代碼:
一個按鈕,點擊之后創建一個陣列,執行一些計算,
很常見的邏輯,
我們最后加了一個 console.log 列印了下這個陣列,
起個靜態服務:
瀏覽器訪問:
點擊 performance 下的垃圾回收按鈕,手動觸發一次 GC:
勾選 Memory,然后開始錄制,點擊 3 次按鈕,再執行一次 GC:
你會發現記憶體是這樣的:
記憶體占用有三次增長,因為我們點擊三次按鈕的時候會創建 3 次大陣列,
但是最后我們手動 GC 之后并沒有回落下去,也就是這個大陣列沒有被回收,
按理來說,代碼執行完,那用的記憶體就要被釋放,然后再執行別的代碼,結果這段代碼執行完之后大陣列依然占據著記憶體,這樣別的代碼再執行的時候可用記憶體就少了,
這就是發生了記憶體泄漏,也就是代碼執行完了不釋放記憶體的流氓行為,
有同學說,只是這么一點記憶體問題不大呀,反正可用記憶體還很多,
但如果你的代碼要跑很長時間,這段代碼要執行很多次呢?
每次執行都會占據一部分記憶體不釋放,慢慢的記憶體就不夠用了,甚至會導致程式崩潰,
比如當這段代碼執行個 9 次,記憶體占用就增長了 9 個大陣列的記憶體:
再多執行幾次呢?
是不是就有崩潰的隱患了,
那為啥說是 console.log 導致的呢?
我們來看看不用 console.log 是什么樣的:
注釋掉 console.log,重新跑,
你會發現現在的記憶體分配情況是這樣的:
分配了三次記憶體,但是 GC 后又會落下去了,
這才是沒有記憶體泄漏的好代碼,
那為啥 console.log 會導致記憶體泄漏呢?
因為控制臺列印的物件,你是不是有可能展開看?那如果這個物件在記憶體中沒有了,是不是就看不到了?
所以有這個參考在,瀏覽器不會把你列印的物件的記憶體釋放掉,
有的同學說,那我不打開控制臺,是不是就沒有這個參考了?
答案是否定的:
我點擊了幾次之后,再打開控制臺,依然是可以看到這個物件的,說明沒有被 GC,
也就是說用 console.log 列印物件的代碼一定是有記憶體泄漏的,
當然,也不只是 console.log 會導致記憶體泄漏,還有別的 4 種情況:
- 定時器用完了沒有清除,那每次執行都會多一個定時器的記憶體占用,這就是記憶體泄漏
- 元素從 dom 移除了,但是還有一個變數參考著他,這樣的游離的 dom 元素也不會被回收,每執行一次代碼,就會多出游離的 dom 元素的記憶體,這也是記憶體泄漏
- 閉包參考了某個變數,這個變數不會被回收,如果這樣的閉包比較多,那每次執行都會多出這些被參考變數的記憶體占用,這樣參考大物件的閉包多了之后,也會導致記憶體問題
- 全域變數,這個本來就不會被 GC,要注意全域變數的使用
總之,全域變數、閉包參考的變數、被移除的 dom 依然被參考、定時器用完了沒清除、console.log 都會發生代碼執行完了,但是還占用著一部分記憶體的流氓行為,也就是記憶體泄漏,
注意,這里指的是使用完畢后沒有回收,在使用期間的記憶體增長是正常的,
那怎么排查呢?
performance 工具就可以:
點擊記憶體分配情況的某個點,就會定位到 performance 中的某個任務的代碼,點擊可以在下面看到詳情:
這樣就定位到了分配記憶體的代碼,分析一下哪里會有問題即可,
當然,前提還是要執行先 GC,再做一些操作,再 GC 的這個流程,
這是從代碼角度來分析記憶體泄漏,其實還可以從記憶體中物件的角度,這個是通過 Memory 工具:
先 GC,錄制一次記憶體快照,再點擊幾次按鈕,然后 GC,再錄制一次記憶體快照,
流程和用 performance 分析的時候一樣,
拿到兩次記憶體快照也是可以分析出有記憶體泄漏的:
可以看到 GC 后記憶體占用依然增長了,
快照記錄著這個時刻記憶體中所有物件的狀態:
對比兩次快照,就可以找到變化的部分:
比如這時候可以看到最大的記憶體增長是 array 物件:
然后就可以從 array 的角度去思考是什么導致的記憶體泄漏了,
此外,memory 還有實時分析的工具:
選擇第二個,然后點幾次按鈕:
其實不用手動 GC,JS 引擎會做 GC,
去掉 console.log 再錄制是這樣的:
除了最開始全域變數會分配一些記憶體以外,點擊按鈕之后的記憶體變藍后又變灰了,也就是被 GC 了,
這樣你點多少次按鈕,記憶體占用都沒有增長,
這就是代碼執行完,會回收所有用到的記憶體的好代碼,
而前面的那個是每次代碼執行,都會占用一部分記憶體不釋放的記憶體泄漏代碼,
你還可以看到每一次記憶體分配的物件是啥:
不管是用 Performance 工具還是 Memory 工具,都可以發現 console.log 有記憶體泄漏的問題,所以還是盡量不要用這個來除錯了,
那應該用什么呢?
用 debugger 呀,不管是 vscode debugger 還是 chrome devtools 的都可以:
你可以添加一個 logpoint 來代替 console.log 列印:
代碼執行到這里就會列印:
而你的代碼里不需要寫 console.log,
此外,很多地方可以用斷點代替列印:
可以看到代碼執行路線和作用域,豈不是更高效?
總結
console.log 會導致記憶體泄漏,也就是代碼執行完了,但還占據著一部分記憶體的流氓行為,
除了 console.log,游離的 dom 被變數參考、全域變數、變數被閉包參考、定時器沒清除也會導致記憶體泄漏,
我們可以用 Performance 工具和 Memory 工具分析記憶體泄漏,
先手動 GC,然后執行一些操作,再 GC,如果記憶體沒有回到執行前,就說明這段代碼有記憶體泄漏,可以再用 Performance 定位到代碼位置分析代碼,
Memory 工具是從記憶體物件的角度分析,可以對兩次快照做 diff,看下是啥物件泄漏了,
也可以實時檢測記憶體占用情況,看看是否存在記憶體泄漏,物件是啥,
console.log 除錯效率也不高,可以換成 logpoint,或者打斷點,
千萬不要把 console.log 上生產!不然這樣有記憶體泄漏的代碼,一旦執行時間長了就會有問題,
其實普通專案也還好,不會長期跑,但是類似大屏專案這種長期跑的,一旦有記憶體泄漏,一定會崩潰,只有時間長短的區別,
本文轉載于:
https://juejin.cn/post/7185128318235541563
如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/543579.html
標籤:其他
上一篇:uniapp踩坑必備筆記
下一篇:vuex相關筆記






