我們之前聊過關(guān)于瀏覽器中內(nèi)存是如何管理、垃圾回收集中常見算法歪架、以及V8引擎中如何做垃圾回收股冗。那么又到了一個老生常談的話題 -- “道理我都懂”,我怎么知道我寫的代碼有沒有內(nèi)存問題呢和蚪?接下來就給大家推薦一款工具---Performance
為什么使用Performance
GC的目的是為了實現(xiàn)內(nèi)存空間的良性循環(huán)魁瞪,并且只有合理使用GC才能夠達(dá)到這種良性循環(huán)。那么如何時刻關(guān)注GC是不是合理使用了惠呼,Performance 就給我們提供了多種監(jiān)控方式,讓我們實時關(guān)注我們的內(nèi)存狀態(tài)以及GC的工作狀態(tài)峦耘。
如何使用Performance
- 打開瀏覽器輸入目標(biāo)地址剔蹋,不跳轉(zhuǎn)
- 進(jìn)入開發(fā)者模式,打開性能
- 開啟錄制功能辅髓,開始訪問輸入的地址
- 操作頁面執(zhí)行用戶行為泣崩,一段時間后停止錄制
- 生成過程的內(nèi)存記錄信息,分析信息
如何定位內(nèi)存問題
- 網(wǎng)絡(luò)正常的情況下洛口,頁面出現(xiàn)延遲加載或經(jīng)常性的暫停(可能因為頻繁垃圾回收)
- 頁面持續(xù)性出現(xiàn)糟糕的性能(可能因為內(nèi)存膨脹矫付,內(nèi)存申請過大)
- 頁面的性能隨時間延長越來越差 (內(nèi)存泄露)
界定內(nèi)存問題的標(biāo)準(zhǔn)
- 內(nèi)存泄露: 內(nèi)存使用持續(xù)升高
- 內(nèi)存膨脹: 在多數(shù)設(shè)備上都存在的性能問題,申請值過大第焰,若不同的設(shè)備表現(xiàn)一致买优,則因程序問題
- 頻繁垃圾回收: 通過內(nèi)存變化圖進(jìn)行分析
監(jiān)控內(nèi)存的方式
- 瀏覽器任務(wù)管理器
- Timeline 時序圖記錄
- 堆快照查找分離DOM
- 其他功能判斷是否存在頻繁的垃圾回收
任務(wù)管理器監(jiān)控內(nèi)存
任務(wù)管理器中調(diào)取網(wǎng)頁的javascript內(nèi)存,觀察內(nèi)存是否在一直上漲挺举,如果一直升高杀赢,那么證明內(nèi)存管理存在問題,但是無法判斷是什么導(dǎo)致的該問題
Timeline 記錄內(nèi)存
我們用一段代碼來模擬一下創(chuàng)建大量dom節(jié)點以及創(chuàng)建長度超長的字符串對內(nèi)存的影響湘纵,以及我們?nèi)绾稳ナ褂胻imeline觀測這部分內(nèi)存變化
<body>
<button id="btn">Add</button>
<script>
// 模擬創(chuàng)建大量dom節(jié)點
const btn = document.getElementById("btn")
btn.onclick = () => {
test()
}
const arrList = []
function test() {
for (let i = 0;i< 100000; i++) {
document.body.appendChild(document.createElement("p"))
}
arrList.push(new Array(1000000).join("x"))
}
</script>
</body>
我們使用Performance脂崔,采用之前提到過的方法到了一個監(jiān)控的記錄如下:
我們可以從這部分中觀察到指定時間段的內(nèi)存變化以及此時頁面所處的狀態(tài)便于我們?nèi)ヅ挪閱栴},另外我們也可以從底部的記錄里面觀察到j(luò)s堆梧喷、文檔砌左、node 節(jié)點等等諸多相關(guān)變化信息脖咐,以助于我們?nèi)ダ斫鈨?nèi)存變化以及GC策略的執(zhí)行。
堆快照查找分離DOM
- 界面元素存活在DOM樹上
- 垃圾對象的DOM節(jié)點(從DOM樹上脫離汇歹,js代碼也不在引用)
- 分離狀態(tài)的DOM節(jié)點(從DOM樹上脫離屁擅,但js代碼還在引用)
如何拍攝堆快照
點擊如圖所示的按鈕,就會按照拍攝一張堆快照放在左側(cè)的列表
我們依然模擬一下使用場景
<body>
<button id="btn">Add</button>
<script>
let ulTem
function test() {
let ul = document.createElement("ul")
for (let i = 0;i< 10; i++) {
let li = document.createElement("li")
ul.appendChild(li)
}
ulTem = ul
}
document.getElementById("btn").addEventListener("click", test)
</script>
</body>
代碼中我們可以看到ul是沒有被渲染到頁面上的秤朗,但是它被一個變量給引用了煤蹭,那么就導(dǎo)致他在后續(xù)的GC過程中無法被清除。
如何查看堆快照
我們找到程序執(zhí)行后的代碼發(fā)現(xiàn)取视,的確有ul 以及 li沒有被清理硝皂。
那么如何去解除他們的引用,很簡單 只需要將
ulTem = null
即可
那么以上就是常使用的集中監(jiān)控方式已經(jīng)介紹完了作谭。
判斷是否存在頻繁GC
- GC工作時應(yīng)用程序是停止的
- 頻繁且時間過長的GC常導(dǎo)致應(yīng)用假死
- 用戶使用中感知應(yīng)用卡頓
所以需要我們?nèi)ゴ_實是否存在頻繁的垃圾回收并且去避免
那么如何確定頻繁的垃圾回收稽物?
- Timeline 中頻繁的短時間內(nèi)上升下降
- 任務(wù)管理器中數(shù)據(jù)頻繁的迅速增加迅速減小