內(nèi)存的釋放流程:
- 分配內(nèi)存
- 內(nèi)存中的讀寫
- 垃圾回收
對(duì)于內(nèi)存的使用,所有語言基本都是一樣的,只是更底層的語言在對(duì)于 ”分配內(nèi)存“ 和 ”使用內(nèi)存“ 是明確的,但是在高級(jí)語言中(比如本文的 JS)是隱藏了。
JS 中在定義一個(gè)變量時(shí),就已經(jīng)分配好了一個(gè)內(nèi)存;
同時(shí),內(nèi)部也提供好了垃圾回收的機(jī)制,回收那些已經(jīng)不再使用的內(nèi)存。
原理:
- 當(dāng)我們定義了一個(gè)變量后,這個(gè)變量就會(huì)被垃圾回收機(jī)制所標(biāo)記;
- 當(dāng)一次程序執(zhí)行以后,如果這個(gè)變量依然存在引用,則垃圾回收機(jī)制會(huì)認(rèn)為:變量還在使用,不能釋放
- 內(nèi)存泄漏的原因:程序任務(wù)一個(gè)變量已經(jīng)沒用了,可是垃圾回收機(jī)制認(rèn)為他還在使用,從而導(dǎo)致這段內(nèi)存無法釋放。
- 這里需要注意的是:是程序?qū)@段內(nèi)存失去了控制權(quán)。
- 內(nèi)存突然暴增,并不是內(nèi)存泄漏。
上圖中,我錄制了一個(gè)最基礎(chǔ)的內(nèi)存使用:在百度中(input)輸入文字,觸發(fā)高頻 change
事件:
于是我們得到了上圖中的這條監(jiān)聽內(nèi)存的曲線:
- 這條藍(lán)色的線條中,我用黃色色圈出來的部分是手動(dòng)清理了內(nèi)存后,內(nèi)存驟降的兩個(gè)時(shí)機(jī)
- 黃色圈出來的部分是指程序中,在我操作前后內(nèi)存的變化,可以看到這里錄制前后(停止輸入后)內(nèi)存的使用并沒有多出來內(nèi)存,說明這里的 GC 后內(nèi)存的控制在程序可掌控的范圍內(nèi)。
以上就是一個(gè)簡單的內(nèi)存完整釋放的例子。
那么有哪些場(chǎng)景容易造成內(nèi)存泄露呢?
一、全局變量
分析上圖,我們?cè)诮o window 變量設(shè)置了十萬個(gè)屬性,在這個(gè)全局變量下的內(nèi)存是不會(huì)被垃圾回收的,這里多出來的那一步分內(nèi)存就是程序失去對(duì)這些變量控制權(quán)的部分:
所以意外的全局變量泄露
二、console.log()
上圖執(zhí)行一段打印邏輯;
將上述結(jié)果放大后,可以清晰的看到,兩次清理 GC 后,內(nèi)存得到了一定的釋放,但是有超出的那一部分內(nèi)存造成了內(nèi)存泄漏:
console.log 也是全局變量
這也是為什么,生產(chǎn)環(huán)境中都會(huì)要求刪除 console 的原因了
當(dāng)然,讓客戶看到 console 丟人也是一個(gè)原因
三、閉包
閉包本身并不會(huì)造成內(nèi)存泄漏,沒有控制好閉包的使用,導(dǎo)致變量的引用無法被回收才是閉包導(dǎo)致內(nèi)存泄漏的原因。
直接看兩次清除 GC 后的情況:
可以看到第二次清除 GC 后,依然有一部分內(nèi)存沒有得到釋放,這部分就是閉包引用導(dǎo)致的內(nèi)存泄漏。
而常規(guī)的閉包引用的函數(shù)執(zhí)行并不會(huì)造成內(nèi)存泄漏。
四、Dom 泄漏
現(xiàn)代的前端框架幾乎都不推薦直接操作 dom 了,因?yàn)?dom 也是對(duì)象,創(chuàng)建的 dom 對(duì)象在被使用后,沒有及時(shí)清理掉也會(huì)造成一定程度的內(nèi)存泄漏。
總結(jié)
所謂內(nèi)存泄漏就是程序執(zhí)行完了,本該隨著程序執(zhí)行結(jié)束而被釋放的內(nèi)存由于有著引用關(guān)系而未得到釋放導(dǎo)致的內(nèi)存占用問題。文章來源:http://www.zghlxwxcb.cn/news/detail-430697.html
小結(jié)一下防止內(nèi)存泄漏的幾個(gè)方面:文章來源地址http://www.zghlxwxcb.cn/news/detail-430697.html
- 清除不必要的引用
- 盡量不要定義全局變量(比如減少 var 操作符的使用)
- 提交代碼前刪除 console
到了這里,關(guān)于JavaScript 內(nèi)存泄漏的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!